igniteui-webcomponents
Version:
Ignite UI for Web Components is a complete library of UI components, giving you the ability to build modern web applications using encapsulation and the concept of reusable components in a dependency-free approach.
194 lines • 6.4 kB
JavaScript
const FLAGS = new Set('aACL09#&?');
const REGEX = new Map([
['C', /(?!^$)/u],
['&', /[^\p{Separator}]/u],
['a', /[\p{Letter}\d\p{Separator}]/u],
['A', /[\p{Letter}\d]/u],
['?', /[\p{Letter}\p{Separator}]/u],
['L', /\p{Letter}/u],
['0', /\d/],
['9', /[\d\p{Separator}]/u],
['#', /[\d\-+]/],
]);
const REQUIRED = new Set('0#LA&');
const replaceIMENumbers = (string) => {
return string.replace(/[0123456789]/g, (num) => ({
'1': '1',
'2': '2',
'3': '3',
'4': '4',
'5': '5',
'6': '6',
'7': '7',
'8': '8',
'9': '9',
'0': '0',
})[num]);
};
export class MaskParser {
constructor(options = { format: 'CCCCCCCCCC', promptCharacter: '_' }) {
this.literals = new Map();
this._escapedMask = '';
this.options = options;
this.parseMaskLiterals();
}
get literalPositions() {
return Array.from(this.literals.keys());
}
get escapedMask() {
return this._escapedMask;
}
get mask() {
return this.options.format;
}
set mask(value) {
this.options.format = value || this.options.format;
this.parseMaskLiterals();
}
get prompt() {
return this.options.promptCharacter;
}
set prompt(value) {
this.options.promptCharacter = value
? value.substring(0, 1)
: this.options.promptCharacter;
}
parseMaskLiterals() {
this.literals.clear();
this._escapedMask = this.mask;
for (let i = 0, j = 0; i < this.mask.length; i++, j++) {
const [current, next] = [this.mask.charAt(i), this.mask.charAt(i + 1)];
if (current === '\\' && FLAGS.has(next)) {
this._escapedMask = this.replaceCharAt(this._escapedMask, j, '');
this.literals.set(j, next);
i++;
}
else if (!FLAGS.has(current)) {
this.literals.set(j, current);
}
}
}
isPromptChar(char) {
return char === this.prompt;
}
replaceCharAt(string, pos, char) {
return `${string.substring(0, pos)}${char}${string.substring(pos + 1)}`;
}
validate(char, maskedChar) {
const regex = REGEX.get(maskedChar);
return regex ? regex.test(char) : false;
}
getNonLiteralPositions(mask = '') {
const positions = this.literalPositions;
const result = [];
const iter = Array.from(mask).entries();
for (const [pos, _] of iter) {
if (!positions.includes(pos)) {
result.push(pos);
}
}
return result;
}
getRequiredNonLiteralPositions(mask) {
const positions = this.literalPositions;
const result = [];
const iter = Array.from(mask).entries();
for (const [pos, char] of iter) {
if (REQUIRED.has(char) && !positions.includes(pos)) {
result.push(pos);
}
}
return result;
}
getPreviousNonLiteralPosition(start) {
const positions = this.literalPositions;
for (let i = start; i > 0; i--) {
if (!positions.includes(i))
return i;
}
return start;
}
getNextNonLiteralPosition(start) {
const positions = this.literalPositions;
for (let i = start; i < this._escapedMask.length; i++) {
if (!positions.includes(i))
return i;
}
return start;
}
replace(maskString, value, start, end) {
let masked = maskString ?? '';
const chars = Array.from(replaceIMENumbers(value));
const positions = this.literalPositions;
const final = Math.min(end, masked.length);
let cursor = start;
for (let i = start; i < final || (chars.length && i < masked.length); i++) {
if (positions.includes(i)) {
if (chars[0] === masked[i]) {
cursor = i + 1;
chars.shift();
}
continue;
}
if (chars[0] &&
!this.validate(chars[0], this._escapedMask[i]) &&
!this.isPromptChar(chars[0])) {
break;
}
let char = this.prompt;
if (chars.length) {
cursor = i + 1;
char = chars.shift();
}
masked = this.replaceCharAt(masked, i, char);
}
return { value: masked, end: cursor };
}
parse(masked = '') {
const positions = this.literalPositions;
const result = [];
const iter = Array.from(masked).entries();
for (const [pos, char] of iter) {
!positions.includes(pos) && !this.isPromptChar(char)
? result.push(char)
: result.push('');
}
return result.join('');
}
isValidString(input = '') {
const required = this.getRequiredNonLiteralPositions(this._escapedMask);
if (required.length > this.parse(input).length) {
return false;
}
return required.every((pos) => {
const char = input.charAt(pos);
return (this.validate(char, this._escapedMask.charAt(pos)) &&
!this.isPromptChar(char));
});
}
apply(input = '') {
const output = new Array(this._escapedMask.length).fill(this.prompt);
for (const [pos, char] of this.literals.entries()) {
output[pos] = char;
}
if (!input) {
return output.join('');
}
const nonLiteralPositions = this.getNonLiteralPositions(this._escapedMask);
const values = nonLiteralPositions.map((pos, index) => {
const char = input.charAt(index);
return !this.validate(char, this._escapedMask.charAt(pos)) &&
!this.isPromptChar(char)
? this.prompt
: char;
});
if (values.length > nonLiteralPositions.length) {
values.splice(nonLiteralPositions.length);
}
for (const [position, char] of values.entries()) {
output[nonLiteralPositions[position]] = char;
}
return output.join('');
}
}
//# sourceMappingURL=mask-parser.js.map