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.
211 lines • 6.89 kB
JavaScript
const MASK_FLAGS = new Set('aACL09#&?');
const MASK_REQUIRED_FLAGS = new Set('0#LA&');
const MASK_PATTERNS = new Map([
['C', /(?!^$)/u],
['&', /[^\p{Separator}]/u],
['a', /[\p{Letter}\p{Number}\p{Separator}]/u],
['A', /[\p{Letter}\p{Number}]/u],
['?', /[\p{Letter}\p{Separator}]/u],
['L', /\p{Letter}/u],
['0', /\p{Number}/u],
['9', /[\p{Number}\p{Separator}]/u],
['#', /[\p{Number}\-+]/u],
]);
function 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]);
}
function validate(char, flag) {
return MASK_PATTERNS.get(flag)?.test(char) ?? false;
}
const MaskDefaultOptions = {
format: 'CCCCCCCCCC',
promptCharacter: '_',
};
export class MaskParser {
get literalPositions() {
return this._literalPositions;
}
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;
}
constructor(options) {
this._literals = new Map();
this._literalPositions = new Set();
this._escapedMask = '';
this._options = { ...MaskDefaultOptions, ...options };
this._parseMaskLiterals();
}
_parseMaskLiterals() {
const mask = this.mask;
const length = mask.length;
const escapedMaskChars = [];
let currentPos = 0;
this._literals.clear();
for (let i = 0; i < length; i++) {
const [current, next] = [mask.charAt(i), mask.charAt(i + 1)];
if (current === '\\' && MASK_FLAGS.has(next)) {
this._literals.set(currentPos, next);
escapedMaskChars.push(next);
i++;
}
else if (MASK_FLAGS.has(current)) {
escapedMaskChars.push(current);
}
else {
this._literals.set(currentPos, current);
escapedMaskChars.push(current);
}
currentPos++;
}
this._escapedMask = escapedMaskChars.join('');
this._literalPositions = new Set(this._literals.keys());
}
_getRequiredNonLiteralPositions() {
const literalPositions = this.literalPositions;
const escapedMask = this._escapedMask;
const length = escapedMask.length;
const result = [];
for (let i = 0; i < length; i++) {
const char = escapedMask[i];
if (MASK_REQUIRED_FLAGS.has(char) && !literalPositions.has(i)) {
result.push(i);
}
}
return result;
}
getPreviousNonLiteralPosition(start) {
const literalPositions = this.literalPositions;
for (let i = start; i > 0; i--) {
if (!literalPositions.has(i)) {
return i;
}
}
return start;
}
getNextNonLiteralPosition(start) {
const literalPositions = this.literalPositions;
const length = this._escapedMask.length;
for (let i = start; i < length; i++) {
if (!literalPositions.has(i)) {
return i;
}
}
return start;
}
replace(maskString, value, start, end) {
const literalPositions = this.literalPositions;
const escapedMask = this._escapedMask;
const length = this._escapedMask.length;
const prompt = this.prompt;
const endBoundary = Math.min(end, length);
const maskedChars = Array.from(maskString || this.apply(''));
const inputChars = Array.from(replaceIMENumbers(value));
const inputLength = inputChars.length;
for (let i = start; i < endBoundary; i++) {
if (!literalPositions.has(i)) {
maskedChars[i] = prompt;
}
}
let cursor = start;
let inputIndex = 0;
let maskPosition = start;
for (; maskPosition < length && inputIndex < inputLength; maskPosition++) {
if (literalPositions.has(maskPosition)) {
cursor = maskPosition + 1;
continue;
}
const char = inputChars[inputIndex];
if (validate(char, escapedMask[maskPosition]) && char !== prompt) {
maskedChars[maskPosition] = char;
cursor = maskPosition + 1;
inputIndex++;
}
else {
inputIndex++;
maskPosition--;
}
}
while (cursor < length && literalPositions.has(cursor)) {
cursor++;
}
return {
value: maskedChars.join(''),
end: cursor,
};
}
parse(masked = '') {
const literalPositions = this.literalPositions;
const prompt = this.prompt;
const length = masked.length;
let result = '';
for (let i = 0; i < length; i++) {
const char = masked[i];
if (!literalPositions.has(i) && char !== prompt) {
result += char;
}
}
return result;
}
isValidString(input = '') {
const prompt = this.prompt;
return this._getRequiredNonLiteralPositions().every((position) => {
const char = input.charAt(position);
return (validate(char, this._escapedMask.charAt(position)) && char !== prompt);
});
}
apply(input = '') {
const literals = this._literals;
const prompt = this.prompt;
const escapedMask = this._escapedMask;
const length = escapedMask.length;
const inputLength = input.length;
const result = new Array(escapedMask.length).fill(prompt);
for (const [position, literal] of literals.entries()) {
result[position] = literal;
}
if (!input) {
return result.join('');
}
let inputIndex = 0;
for (let i = 0; i < length; i++) {
if (inputIndex >= inputLength) {
break;
}
if (literals.has(i)) {
continue;
}
if (validate(input.charAt(inputIndex), escapedMask.charAt(i))) {
result[i] = input.charAt(inputIndex);
}
inputIndex++;
}
return result.join('');
}
}
//# sourceMappingURL=mask-parser.js.map