From 615c597897cf011088aeecf00b847089f612687d Mon Sep 17 00:00:00 2001 From: Alexander Shabunevich Date: Wed, 2 Jul 2025 13:00:01 +0300 Subject: [PATCH] feat: use RegExp 'u' flag by default --- src/mask.ts | 5 ++++- src/parser.ts | 11 ++++++++++- test/input.test.ts | 22 ++++++++++++++++++++++ test/mask.test.ts | 13 +++++++++++++ 4 files changed, 49 insertions(+), 2 deletions(-) diff --git a/src/mask.ts b/src/mask.ts index 43381b3..3e555e6 100644 --- a/src/mask.ts +++ b/src/mask.ts @@ -1,5 +1,6 @@ import { MaskTokens, tokens } from './tokens' import { processNumber } from './number' +import { supportsUnicodeRegex } from './parser' export type MaskType = string | string[] | ((input: string) => string) | null @@ -32,7 +33,9 @@ export class Mask { for (const token of Object.values(opts.tokens)) { if (typeof token.pattern === 'string') { - token.pattern = new RegExp(token.pattern) + token.pattern = supportsUnicodeRegex() + ? new RegExp(token.pattern, 'u') + : new RegExp(token.pattern) } } } else { diff --git a/src/parser.ts b/src/parser.ts index 0ad0b13..b23ce87 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -57,7 +57,7 @@ const parseTokens = (value: string): MaskTokens => { value.split('|').forEach((token) => { const parts = token.split(':') tokens[parts[0]] = { - pattern: new RegExp(parts[1]), + pattern: supportsUnicodeRegex() ? new RegExp(parts[1], 'u') : new RegExp(parts[1]), optional: parts[2] === 'optional', multiple: parts[2] === 'multiple', repeated: parts[2] === 'repeated' @@ -66,3 +66,12 @@ const parseTokens = (value: string): MaskTokens => { return tokens } + +export const supportsUnicodeRegex = (): boolean => { + try { + new RegExp('\\p{L}', 'u') + return true + } catch (e) { + return false + } +} diff --git a/test/input.test.ts b/test/input.test.ts index 11245ee..23bb9ca 100644 --- a/test/input.test.ts +++ b/test/input.test.ts @@ -2162,3 +2162,25 @@ describe('Number mask', () => { expect(input).toHaveValue('1,234') }) }) + +describe('Unicode tokens mask', () => { + test('default number', async () => { + document.body.innerHTML = `` + const input = document.getElementById('input') + new MaskInput(input) + + await user.type(input, '1') + expect(input).toHaveValue('') + + await user.type(input, 'z') + expect(input).toHaveValue('z') + + await user.type(input, 'я') + expect(input).toHaveValue('zя') + + await user.type(input, '1') + expect(input).toHaveValue('zя') + + await user.clear(input) + }) +}) diff --git a/test/mask.test.ts b/test/mask.test.ts index c107ed9..e6adaad 100644 --- a/test/mask.test.ts +++ b/test/mask.test.ts @@ -820,3 +820,16 @@ test('tokens replaced', () => { expect(mask.unmasked('12')).toBe('1') }) + +test('unicode tokens', () => { + const mask = new Mask({ + mask: 'A', + // @ts-expect-error + tokens: { A: { pattern: '[\\p{L}]', multiple: true } } + }) + + expect(mask.masked('1')).toBe('') + expect(mask.masked('z')).toBe('z') + expect(mask.masked('zя')).toBe('zя') + expect(mask.masked('zя1')).toBe('zя') +})