vuestic-ui
Version:
Vue 3 UI Framework
1 lines • 13.8 kB
Source Map (JSON)
{"version":3,"file":"regex.mjs","sources":["../../../../../../src/composables/useInputMask/masks/regex.ts"],"sourcesContent":["import { CursorPosition } from '../cursor'\nimport { type Mask } from '../mask'\nimport { Token, parseTokens } from './parser'\n\nexport type RegexToken = {\n /**\n * Char means it is single char and we can compare input value using simple `===`\n * Regex means we need to use regex to compare input value (e.g. `\\d`, `[a-z]`)\n */\n type: 'char' | 'regex',\n /**\n * Expected character or regex source\n */\n expect: string,\n /**\n * Static means users forced to input this char, meaning masked input can suggest this char\n */\n static: boolean,\n\n /**\n * Dynamic means this char is not forced and can be skipped\n */\n dynamic: boolean\n}\n\ntype PossibleResult = RegexToken[]\n\nexport const normalizeTokens = (tokens: Token[], dynamic = false) => {\n let possibleResults: PossibleResult[] = [[]]\n\n for (const token of tokens) {\n if (token.type === 'group') {\n const newResults: PossibleResult[] = []\n possibleResults.forEach((result) => {\n normalizeTokens(token.tree, dynamic).forEach((result2) => {\n newResults.push([...result, ...result2])\n })\n })\n possibleResults = newResults\n }\n\n if (token.type === 'char' || token.type === 'regex') {\n const newResults: PossibleResult[] = []\n possibleResults.forEach((result) => {\n newResults.push([...result, {\n type: token.type,\n expect: token.expect,\n static: token.type === 'char', // && (!dynamic || result.length > 0),\n dynamic: dynamic,\n }])\n })\n possibleResults = newResults\n }\n\n if (token.type === 'repeated') {\n const possibleResults2: PossibleResult[] = []\n for (let i = token.min; i <= token.max && i <= 100; i++) {\n const isDynamic = i !== token.min\n\n normalizeTokens(token.tree, isDynamic || dynamic).forEach((result) => {\n const repeated = (new Array(i).fill(result)).flat() as RegexToken[]\n possibleResults2.push(repeated)\n })\n }\n\n const newResults: PossibleResult[] = []\n possibleResults.forEach((result) => {\n possibleResults2.forEach((result2) => {\n newResults.push([...result, ...result2])\n })\n })\n possibleResults = newResults\n }\n\n if (token.type === 'or regex') {\n const newPossibleResults: PossibleResult[] = []\n\n possibleResults.forEach((existingResult) => {\n normalizeTokens(token.left, true).forEach((result) => {\n newPossibleResults.push([...existingResult, ...result])\n })\n\n normalizeTokens(token.right, true).forEach((result) => {\n newPossibleResults.push([...existingResult, ...result])\n })\n })\n\n possibleResults = newPossibleResults\n }\n }\n\n return possibleResults\n .reduce((acc, result) => {\n if (acc.find((r) => r.length === result.length && r.every((t, i) => t.expect === result[i].expect))) {\n return acc\n }\n\n return [...acc, result]\n }, [] as PossibleResult[])\n}\n\nexport const compareWithMask = (mask: PossibleResult, value: string) => {\n if (!value) { return true }\n\n for (let i = 0; i < mask.length; i++) {\n if (value[i] === undefined) {\n return true\n }\n if (mask[i].type === 'char' && mask[i].expect !== value?.[i]) {\n return false\n }\n\n if (mask[i].type === 'regex' && !new RegExp(mask[i].expect).test(value[i])) {\n return false\n }\n }\n\n return value.length <= mask.length\n}\n\nconst compareWithToken = (token: Token, value: string) => {\n if (token.type === 'char' && token.expect !== value) {\n return false\n }\n\n if (token.type === 'regex' && !new RegExp(token.expect).test(value)) {\n return false\n }\n\n return true\n}\n\nconst formatByRegexTokens = (possibleResults: PossibleResult[], value: string, reverse = false) => {\n if (reverse) {\n possibleResults = possibleResults.map((result) => result.slice().reverse())\n value = value.split('').reverse().join('')\n }\n\n // TODO: Maybe optimize this?\n let suggestedCharsCount = 0\n let text = ''\n let valueOffset = 0\n let tokensOffset = 0\n\n const maxPossibleMask = possibleResults.reduce((acc, mask) => Math.max(acc, mask.length), 0)\n const foundTokens: (RegexToken)[] = []\n\n while (valueOffset < value.length || tokensOffset < maxPossibleMask) {\n // Filter out possible results that not match with current text\n possibleResults = possibleResults\n .filter((tokens) => {\n return compareWithMask(tokens, text)\n })\n\n const possibleToken = possibleResults\n .map((mask) => mask[tokensOffset])\n .filter((token) => token !== undefined)\n\n if (possibleToken.length === 0) {\n break\n }\n\n const possibleSuggestions = possibleToken.filter((token) => token.type === 'char')\n\n const staticCharts = possibleToken.filter((token) => token.static)\n\n const isOnePossibleStaticChar = staticCharts.reduce((acc, char) => {\n if (acc === null) {\n return char\n }\n\n if (acc.expect !== char.expect) {\n return null\n }\n\n return acc\n }, null as RegexToken | null)\n\n if (possibleSuggestions.length > 0) {\n const suggestedChar = possibleSuggestions[0]?.expect ?? ''\n let canBeSuggested = possibleSuggestions.every((token) => token.expect === suggestedChar) && value[valueOffset]?.length > 0\n\n const onlyStaticLeft = possibleResults.length === 1 && possibleResults[0].slice(tokensOffset).every((token) => token.static)\n\n if (possibleSuggestions[0].dynamic) {\n canBeSuggested = canBeSuggested && value[valueOffset]?.length > 0\n }\n\n if (isOnePossibleStaticChar && value[valueOffset]?.length > 0) {\n canBeSuggested = value[valueOffset] !== isOnePossibleStaticChar.expect\n }\n\n if (possibleToken.some((token) => compareWithToken(token, value[valueOffset]))) {\n canBeSuggested = false\n }\n\n if (onlyStaticLeft) {\n canBeSuggested = true\n }\n\n if (canBeSuggested) {\n if (suggestedChar !== value[valueOffset]) {\n text += suggestedChar\n foundTokens.push(possibleSuggestions[0])\n tokensOffset += 1\n suggestedCharsCount += 1\n continue\n }\n }\n }\n\n if (valueOffset >= value.length) {\n break\n }\n\n const charCorrectTokens = possibleToken.filter((token) => {\n if (token.type === 'char') {\n return token.expect === value[valueOffset]\n }\n\n if (token.type === 'regex') {\n return new RegExp(token.expect).test(value[valueOffset])\n }\n\n return false\n })\n\n if (value[valueOffset] !== undefined) {\n if (charCorrectTokens.length > 0) {\n text += value[valueOffset]\n foundTokens.push(charCorrectTokens[0])\n tokensOffset++\n }\n }\n\n valueOffset++\n }\n\n if (reverse) {\n return {\n text: text.split('').reverse().join(''),\n tokens: foundTokens.reverse(),\n data: suggestedCharsCount,\n }\n }\n\n return {\n text,\n tokens: foundTokens,\n data: suggestedCharsCount,\n }\n}\n\nconst unformat = (text: string, tokens: RegexToken[]) => {\n const value = text\n\n if (!value) { return '' }\n\n return tokens.reduce((acc, token, i) => {\n if (token.static) {\n return acc\n }\n\n if (compareWithToken(token, value[i]) && value[i] !== undefined) {\n return acc + value[i]\n }\n\n return acc\n }, '')\n}\n\nexport const createRegexMask = (regex: RegExp, options = { reverse: false }): Mask<RegexToken> => {\n const tokens = parseTokens(regex.source)\n const possibleResults = normalizeTokens(tokens)\n\n return {\n format: (text: string) => {\n return formatByRegexTokens(possibleResults, text, options.reverse)\n },\n handleCursor (cursorStart, cursorEnd, oldTokens, newTokens, data, suggestedCount = 0) {\n cursorStart.updateTokens(newTokens, options.reverse)\n cursorEnd.updateTokens(newTokens, options.reverse)\n\n if (!options.reverse) {\n cursorStart.moveForward(data.length, CursorPosition.AfterChar)\n cursorEnd.position = cursorStart.position\n } else {\n cursorStart.position = cursorEnd.position\n }\n },\n unformat,\n }\n}\n"],"names":[],"mappings":"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"}