{"version":3,"sources":["../src/index.ts","../src/parseNumber.ts"],"sourcesContent":["export { parseNumber } from './parseNumber';\nexport type { ParseOptions } from './parseNumber';\n","/**\n * Options for parsing numbers with different format support.\n */\ninterface ParseOptions {\n  /** Strip any Unicode currency symbol (e.g. $, €, ₪, ₿). Default: true */\n  stripCurrency?: boolean;\n  /** Allow Swiss-style apostrophe grouping (both ' and '). Default: true */\n  allowApostrophe?: boolean;\n  /** Allow scientific notation like 1.5e3. Default: false */\n  allowScientific?: boolean;\n}\n\n// Pre-compiled regex patterns for performance\nconst REGEX_PATTERNS = {\n  // Swiss apostrophe patterns (regular ' and curly ’)\n  apostrophe: /['\\u2019']/g,\n  swissWithDot: /^\\d{1,3}(['\\u2019']\\d{3})*(\\.\\d+)?$/,\n  swissWithComma: /^\\d{1,3}(['\\u2019']\\d{3})*(,\\d+)?$/,\n  swissSingleDot: /^\\d{1,3}['\\u2019']\\d{3}(\\.\\d+)?$/,\n  swissSingleComma: /^\\d{1,3}['\\u2019']\\d{3}(,\\d+)?$/,\n  \n  // Number format patterns\n  usWithDecimal: /^\\d{1,3}(,\\d{3})*(\\.\\d+)?$/,\n  euWithDecimal: /^\\d{1,3}(\\.\\d{3})*(,\\d+)?$/,\n  pureGroupedCommas: /^\\d{1,3}(,\\d{3})+$/,\n  pureGroupedDots: /^\\d{1,3}(\\.\\d{3})+$/,\n  plainDecimalComma: /^\\d+,\\d+$/,\n  plainDecimalDot: /^\\d+\\.\\d+$/,\n  plainDigits: /^\\d+$/,\n  leadingDecimal: /^[.,]\\d+$/,\n  scientific: /^([+-]?\\d+(?:[.,]\\d+)?)[eE]([+-]?\\d+)$/,\n} as const;\n\n/**\n * Parses scientific notation if enabled and valid.\n */\nfunction parseScientificNotation(s: string, allowScientific: boolean): number | null {\n  if (!allowScientific && /[eE]/.test(s)) {\n    return null; // Reject scientific notation if not allowed\n  }\n  \n  if (allowScientific && /[eE]/.test(s)) {\n    const match = s.match(REGEX_PATTERNS.scientific);\n    if (match) {\n      const [, base, exponent] = match;\n      const normalizedBase = base.replace(',', '.');\n      const num = Number.parseFloat(normalizedBase + 'e' + exponent);\n      if (!Number.isNaN(num)) {\n        return num;\n      }\n    }\n    return null; // Invalid scientific notation\n  }\n  \n  return null; // No scientific notation found\n}\n\n/**\n * Validates and processes Swiss-style apostrophes.\n */\nfunction processSwissApostrophes(s: string, allowApostrophe: boolean): string | null {\n  if (!REGEX_PATTERNS.apostrophe.test(s)) {\n    return s; // No apostrophes found\n  }\n  \n  if (!allowApostrophe) {\n    return null; // Apostrophes not allowed\n  }\n  \n  // Validate Swiss format patterns\n  const isValid = \n    REGEX_PATTERNS.swissWithDot.test(s) ||\n    REGEX_PATTERNS.swissWithComma.test(s) ||\n    REGEX_PATTERNS.swissSingleDot.test(s) ||\n    REGEX_PATTERNS.swissSingleComma.test(s);\n    \n  if (!isValid) {\n    return null; // Invalid apostrophe usage\n  }\n  \n  // Remove apostrophes after validation\n  return s.replace(REGEX_PATTERNS.apostrophe, '');\n}\n\n/**\n * Parses a string into a number with support for multiple international formats.\n *\n * Supports US (1,234.56), European (1.234,56), and Swiss (1'234.56) number formats.\n * Validates proper thousands separators and decimal points according to locale conventions.\n *\n * @param value - The string to parse into a number\n * @param options - Configuration options for parsing behavior\n * @returns The parsed number, or null if the input is invalid\n *\n * @example\n * ```typescript\n * parseNumber('1,234.56');     // → 1234.56 (US format)\n * parseNumber('1.234,56');     // → 1234.56 (EU format)\n * parseNumber(\"1'234.56\");     // → 1234.56 (Swiss format)\n * parseNumber('₪1,234.56');    // → 1234.56 (currency symbol removed)\n * parseNumber('1.5e3');        // → null (scientific notation disabled by default)\n * parseNumber('1.5e3', { allowScientific: true }); // → 1500\n * parseNumber('invalid');      // → null\n * ```\n */\nconst parseNumber = (\n  value: string,\n  options: ParseOptions = {}\n): number | null => {\n  if (value == null) return null;\n\n  // Set default options\n  const {\n    stripCurrency = true,\n    allowApostrophe = true,\n    allowScientific = false,\n  } = options;\n\n  // Normalize Unicode minus and trim spaces\n  let s = String(value)\n    .replace(/\\u2212/g, \"-\")\n    .trim()\n    .replace(/\\s+/g, \"\");\n\n  // Remove currency symbols if enabled\n  if (stripCurrency) {\n    s = s.replace(/\\p{Sc}/gu, \"\");\n  }\n\n  if (s === \"\") return null;\n\n  // Handle scientific notation early (before sign processing)\n  const scientificResult = parseScientificNotation(s, allowScientific);\n  if (scientificResult !== null) {\n    return scientificResult;\n  }\n\n  // Extract and preserve the sign\n  let isNegative = false;\n  if (s.startsWith(\"-\")) {\n    isNegative = true;\n    s = s.substring(1).trim(); // Remove minus and trim any spaces after it\n    if (s === \"\") return null; // Just a minus sign is invalid\n  } else if (s.startsWith(\"+\")) {\n    // Remove explicit + sign (positive is default)\n    s = s.substring(1).trim();\n    if (s === \"\") return null; // Just a plus sign is invalid\n  }\n\n  // Reject signs elsewhere in the string\n  if (s.includes(\"-\") || s.includes(\"+\")) return null;\n\n  // Validate and remove Swiss-style apostrophes (must be proper 3-digit grouping)\n  const apostropheResult = processSwissApostrophes(s, allowApostrophe);\n  if (apostropheResult === null) {\n    return null; // Invalid apostrophe usage or not allowed\n  }\n  s = apostropheResult;\n\n  // Normalize leading decimals: \".5\" / \",5\" -> \"0.5\"\n  if (REGEX_PATTERNS.leadingDecimal.test(s)) s = \"0\" + s;\n\n  const hasDot = s.includes(\".\");\n  const hasComma = s.includes(\",\");\n\n  if (hasDot && hasComma) {\n    // Disambiguate by last separator → that one is decimal\n    if (s.lastIndexOf(\".\") > s.lastIndexOf(\",\")) {\n      if (!REGEX_PATTERNS.usWithDecimal.test(s)) return null;\n      s = s.replace(/,/g, \"\");\n    } else {\n      if (!REGEX_PATTERNS.euWithDecimal.test(s)) return null;\n      s = s.replace(/\\./g, \"\").replace(\",\", \".\");\n    }\n  } else if (hasComma) {\n    // Only commas → disambiguate\n    const [intPart] = s.split(\",\");\n    if (\n      // Grouping if it matches valid grouping AND integer part isn't \"0\"\n      REGEX_PATTERNS.pureGroupedCommas.test(s) &&\n      intPart !== \"0\"\n    ) {\n      s = s.replace(/,/g, \"\");\n    } else if (REGEX_PATTERNS.plainDecimalComma.test(s)) {\n      // Otherwise treat as decimal\n      s = s.replace(\",\", \".\");\n    } else if (REGEX_PATTERNS.plainDigits.test(s.replace(/,/g, \"\"))) {\n      return null;\n    } else {\n      return null;\n    }\n  } else if (hasDot) {\n    // Only dots → disambiguate\n    const [intPart] = s.split(\".\");\n    if (\n      // Grouping if it matches valid grouping AND integer part isn't \"0\"\n      REGEX_PATTERNS.pureGroupedDots.test(s) &&\n      intPart !== \"0\"\n    ) {\n      s = s.replace(/\\./g, \"\");\n    } else if (REGEX_PATTERNS.plainDecimalDot.test(s)) {\n      // Otherwise treat as decimal\n      // keep as-is\n    } else if (REGEX_PATTERNS.plainDigits.test(s.replace(/\\./g, \"\"))) {\n      return null;\n    } else {\n      return null;\n    }\n  } else if (!REGEX_PATTERNS.plainDigits.test(s)) {\n    return null;\n  }\n\n  const absNum = Number.parseFloat(s);\n  if (Number.isNaN(absNum)) return null;\n\n  let out = isNegative ? -absNum : absNum;\n\n  // Normalize negative zero to 0\n  if (out === 0) out = 0;\n\n  return out;\n};\n\nexport { parseNumber, type ParseOptions };\n"],"mappings":"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","names":[]}