{"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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"}