vuestic-ui
Version:
Vue 3 UI Framework
1 lines • 9.7 kB
Source Map (JSON)
{"version":3,"file":"parser.mjs","sources":["../../../../../../src/composables/useInputMask/masks/parser.ts"],"sourcesContent":["/* eslint-disable no-use-before-define */\ninterface TokenBase {\n type: string\n expect: string\n}\n\ninterface TokenChar extends TokenBase {\n type: 'char'\n}\n\ninterface TokenRegex extends TokenBase {\n type: 'regex'\n}\n\ninterface TokenRepeated extends TokenBase {\n type: 'repeated',\n tree: Token[]\n min: number,\n max: number,\n content: string\n}\n\ninterface TokenGroup extends TokenBase {\n type: 'group',\n tree: Token[]\n}\n\ninterface TokenOrRegex extends TokenBase {\n type: 'or regex',\n left: Token[],\n right: Token[]\n}\n\nexport type Token = TokenChar | TokenRegex | TokenRepeated | TokenGroup | TokenOrRegex\n\nconst or = (...args: RegExp[]) => new RegExp(args.map((r) => r.source).join('|'), 'g')\n\nconst TOKEN_SPLIT_REGEX = or(\n /(\\{[^}]*\\})/, // Token required to have limits {1, 3}, {1,}, {1}\n /(\\\\[dws.])/,\n /(^\\([^)]*\\)$)/, // group like (test)\n /(\\[[^\\]]*\\])/, // split by [^3]{1}, [a-z], [0-9]{1, 3}\n /(?:)/, // split for each letter\n)\n\n/**\n * Checks if the symbol contains correct (.)\n *\n * @example\n * `(.)(.)` must be invalid - two groups\n * `((.)(.))` is valid - single group with nested groups\n */\nconst isMaskSingleGroup = (symbol: string) => {\n if (!symbol.startsWith('(') || !symbol.endsWith(')')) { return false }\n\n let groupDepth = 0\n for (let i = 0; i < symbol.length; i++) {\n const char = symbol[i]\n if (char === '(') {\n groupDepth += 1\n } else if (char === ')') {\n groupDepth -= 1\n\n if (groupDepth === 0 && i !== symbol.length - 1) {\n return false\n }\n }\n }\n\n return groupDepth === 0\n}\n\n/**\n * Parse raw tokens (strings). Split tokens into groups: char, (), {}, [], etc.\n *\n * @example\n *\n * `(.)(.){1,2}` -> ['(.)', '(.){1,2}']\n * `((.)|(.)){2}text(.)` -> ['((.)|(.)){2}', 'text', '(.)']\n */\nconst parseRawTokens = (symbol: string) => {\n let group = 0\n const groups = []\n let currentChunk = ''\n\n let i = 0\n\n while (i < symbol.length) {\n if (symbol[i] === '(' && symbol[i - 1] !== '\\\\') {\n if (group === 0 && currentChunk.length > 0) {\n groups.push(...currentChunk.split(TOKEN_SPLIT_REGEX).filter((v) => v !== '' && v !== undefined))\n currentChunk = ''\n }\n group += 1\n }\n\n currentChunk += symbol[i]\n\n if (symbol[i] === ')' && symbol[i - 1] !== '\\\\') {\n group -= 1\n\n if (group === 0 && currentChunk.length > 0) {\n groups.push(currentChunk)\n currentChunk = ''\n }\n }\n\n i++\n }\n\n if (currentChunk.length > 0) {\n groups.push(...currentChunk.split(TOKEN_SPLIT_REGEX).filter((v) => v !== '' && v !== undefined))\n }\n\n return groups\n .map((g) => g.replace(/^\\?[:!>]/, '')) // Remove group modifiers\n .filter((v) => v !== '' && v !== undefined)\n}\n\n// TODO: Maybe add more symbols to support\nconst RESERVED_SLASH_SYMBOLS = ['d', 'D', 'w', 'W', 's', 'S', '.']\n\nconst MAX_REPEATED = 10\n\n/** Build ast of tokens */\nexport const parseTokens = (mask: string, directlyInGroup = false): Token[] => {\n let tokens: Token[] = []\n\n // Handle or in group, if single group - treat as directly in group\n if (isMaskSingleGroup(mask)) {\n mask = mask.slice(1, -1) // Remove brackets\n directlyInGroup = true\n }\n\n const rawTokens = parseRawTokens(mask)\n\n for (let i = 0; i < rawTokens.length; i++) {\n const rawToken = rawTokens[i]\n\n if (rawToken === '\\\\') {\n // Ignore \\, it is used in pair with next token\n continue\n }\n\n if (!RESERVED_SLASH_SYMBOLS.includes(rawToken) && rawTokens[i - 1] === '\\\\') {\n tokens.push({ type: 'char', expect: rawToken })\n continue\n }\n\n if (rawToken === '|') {\n if (directlyInGroup) {\n tokens = [{\n type: 'or regex',\n expect: mask,\n left: [...tokens],\n right: parseTokens(`(${rawTokens.slice(i + 1).join('')})`),\n }]\n\n break\n }\n\n const prevToken = tokens.pop()!\n const nextToken = parseTokens(rawTokens[i + 1])\n\n tokens.push({\n type: 'or regex',\n expect: `${prevToken}|${rawTokens[i + 1]}`,\n left: [prevToken],\n right: nextToken,\n })\n\n continue\n }\n\n if (rawToken.startsWith('{') && rawToken.endsWith('}') && rawToken.length > 2) {\n const [v, min, delimiter, max] = rawToken.split(/\\{(\\d+)(,\\s?)?(\\d+)?\\}$/)\n\n const prevToken = tokens.pop()!\n\n tokens.push({\n type: 'repeated',\n expect: prevToken.expect + rawToken,\n tree: [prevToken],\n min: parseInt(min),\n max: max ? parseInt(max) : delimiter ? MAX_REPEATED : parseInt(min),\n content: rawToken,\n })\n continue\n }\n\n if (rawToken.endsWith('*')) {\n const prevToken = tokens.pop()!\n tokens.push({ type: 'repeated', expect: prevToken.expect + rawToken, tree: [prevToken], min: 0, max: MAX_REPEATED, content: prevToken.expect })\n continue\n }\n\n if (rawToken.endsWith('+')) {\n const prevToken = tokens.pop()!\n tokens.push({ type: 'repeated', expect: prevToken.expect + rawToken, tree: [prevToken], min: 1, max: MAX_REPEATED, content: prevToken.expect })\n continue\n }\n\n if (rawToken.endsWith('?')) {\n const prevToken = tokens.pop()!\n tokens.push({ type: 'repeated', expect: prevToken.expect + rawToken, tree: [prevToken], min: 0, max: 1, content: prevToken.expect })\n continue\n }\n\n if (['$', '^'].includes(rawToken)) {\n // Ignore start and end of the string - they're not important for masking\n continue\n }\n\n if (rawToken.startsWith('(') && rawToken.endsWith(')')) {\n const tree = parseTokens(rawToken.slice(1, -1), true)\n tokens.push({ type: 'group', expect: rawToken, tree })\n continue\n }\n\n if (rawToken.length === 1 && rawToken !== '.') {\n tokens.push({ type: 'char', expect: rawToken })\n continue\n }\n\n tokens.push({ type: 'regex', expect: rawToken })\n }\n\n return tokens\n}\n"],"names":[],"mappings":"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"}