UNPKG

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.

242 lines 7.74 kB
const MASK_FLAGS = new Set('aACL09#&?'); const MASK_REQUIRED_FLAGS = new Set('0#LA&'); const ESCAPE_CHAR = '\\'; const DEFAULT_FORMAT = 'CCCCCCCCCC'; const DEFAULT_PROMPT = '_'; const ASCII_ZERO = 0x0030; const DIGIT_ZERO_CODEPOINTS = [ ASCII_ZERO, 0x0660, 0x06f0, 0x0966, 0x09e6, 0x0a66, 0x0ae6, 0x0b66, 0x0c66, 0x0ce6, 0x0d66, 0x0e50, 0x0ed0, 0x0f20, 0x1040, 0x17e0, 0x1810, 0xff10, ]; const UNICODE_DIGIT_TO_ASCII = new Map(DIGIT_ZERO_CODEPOINTS.flatMap((zeroCodePoint) => Array.from({ length: 10 }, (_, i) => [ zeroCodePoint + i, String.fromCharCode(ASCII_ZERO + i), ]))); function replaceUnicodeNumbers(text) { const matcher = /\p{Nd}/gu; return text.replace(matcher, (digit) => { return UNICODE_DIGIT_TO_ASCII.get(digit.charCodeAt(0)) ?? digit; }); } const MASK_PATTERNS = new Map([ ['C', /[\s\S]/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 validate(char, flag) { return MASK_PATTERNS.get(flag)?.test(char) ?? false; } const MaskDefaultOptions = { format: DEFAULT_FORMAT, promptCharacter: DEFAULT_PROMPT, }; export class MaskParser { get literalPositions() { return this._literalPositions; } get escapedMask() { return this._escapedMask; } get emptyMask() { return this.apply(); } 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) { const char = value ? value.substring(0, 1) : this._options.promptCharacter; if (MASK_FLAGS.has(char)) { return; } this._options.promptCharacter = char; } constructor(options) { this._literals = new Map(); this._literalPositions = new Set(); this._escapedMask = ''; this._requiredPositions = []; this._options = { ...MaskDefaultOptions, ...options }; this._parseMaskLiterals(); } _isEscapedFlag(char, nextChar) { return char === ESCAPE_CHAR && MASK_FLAGS.has(nextChar); } _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 (this._isEscapedFlag(current, 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()); this._requiredPositions = this._computeRequiredPositions(); } _computeRequiredPositions() { 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 - 1; i >= 0; i--) { if (!literalPositions.has(i)) { return i; } } return 0; } getNextNonLiteralPosition(start) { const literalPositions = this._literalPositions; const length = this._escapedMask.length; for (let i = Math.max(0, start); i < length; i++) { if (!literalPositions.has(i)) { return i; } } return length; } replace(maskString, value, start, end) { const literalPositions = this.literalPositions; const escapedMask = this._escapedMask; const length = escapedMask.length; const prompt = this.prompt; const endBoundary = Math.min(end, length); const maskedChars = maskString ? [...maskString] : [...this.apply('')]; const inputChars = Array.from(replaceUnicodeNumbers(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; const result = []; for (let i = 0; i < length; i++) { const char = masked[i]; if (!literalPositions.has(i) && char !== prompt) { result.push(char); } } return result.join(''); } isValidString(input = '') { const prompt = this.prompt; return this._requiredPositions.every((position) => { const char = input[position]; return validate(char, this._escapedMask[position]) && char !== prompt; }); } apply(input = '') { const literals = this._literals; const prompt = this.prompt; const escapedMask = this._escapedMask; const length = escapedMask.length; const result = new Array(length).fill(prompt); for (const [position, literal] of literals.entries()) { result[position] = literal; } if (!input) { return result.join(''); } const normalizedInput = replaceUnicodeNumbers(input); const inputLength = normalizedInput.length; let inputIndex = 0; for (let i = 0; i < length; i++) { if (inputIndex >= inputLength) { break; } if (literals.has(i)) { continue; } if (validate(normalizedInput[inputIndex], escapedMask[i])) { result[i] = normalizedInput[inputIndex]; } inputIndex++; } return result.join(''); } } //# sourceMappingURL=mask-parser.js.map