{"version":3,"file":"parse.cjs","sources":["../src/parse.ts"],"sourcesContent":["type VariableNode = {\n  type: 'variable';\n  name: string;\n  offset?: PluralOffset;\n  bracketsGroup: number;\n};\ntype PluralNode = {\n  type: 'plural';\n  cardinal: boolean;\n  variable: VariableNode;\n  offset?: PluralOffset;\n  options: {\n    zero?: AstNode[];\n    one?: AstNode[];\n    two?: AstNode[];\n    few?: AstNode[];\n    many?: AstNode[];\n    other?: AstNode[];\n    exacts?: {\n      [value: string]: AstNode[];\n    };\n  };\n};\ntype SelectNode = {\n  type: 'select';\n  variable: VariableNode;\n  options: Record<string, AstNode[]>;\n};\ntype PluralExactValue = {\n  type: 'plural-exact-value';\n  value: string;\n};\ntype PluralOffset = {\n  type: 'plural-offset';\n  rawValue: string;\n  value: number;\n};\ntype ExternalNode<T = any> = {\n  type: 'external';\n  name: string;\n  optionsPart: boolean;\n  variableName: string;\n  data: T;\n  rawData: string;\n};\ntype PureTextNode = {\n  type: 'pure-text';\n  text: string;\n};\nexport type AstNode =\n  | string\n  | VariableNode\n  | PluralNode\n  | PluralExactValue\n  | PluralOffset\n  | SelectNode\n  | ExternalNode\n  | PureTextNode;\n\nexport type ExternalParser<Params = unknown> = (rawData: string, variableName: string, verboseInput?: any) => Params;\nexport type ExternalParsers<Params = unknown> = {\n  [parseName: string]: ExternalParser<Params>;\n};\n\nconst pluralOptions = ['zero', 'one', 'two', 'few', 'many', 'other'];\nconst externals = ['number', 'date', 'time'];\n\nexport type ParseIcuOptions = {\n  externalParsers?: ExternalParsers;\n  verboseParsing?: { [variableName: string]: any };\n  postParsers?: PostParser<AstNode[], AstNode[]>[];\n};\nconst runPostParsers = (ast: AstNode[], postParsers: ParseIcuOptions['postParsers'] = []) =>\n  postParsers.reduce((ast, postParser) => postParser(ast), ast);\n\nexport const parseIcu = (message: string, options: ParseIcuOptions): AstNode[] => {\n  if (!message.includes('{')) return runPostParsers([message], options.postParsers);\n\n  const topLevel: AstNode[] = [];\n  const parentAstChain: AstNode[][] = [];\n  let scopeVariableName: string | null = null;\n  let ast: AstNode[] = topLevel;\n  let prevAstPart: AstNode | null = null;\n  let currentAstPart: AstNode | null = null;\n  let escaping = false;\n  let depth = 0;\n  let bracketsGroupChunkId = 0;\n  const nextPart = (triggerChar: string) => {\n    let currentPart = currentAstPart!;\n    let partConsumed = false;\n    if (typeof currentPart === 'object' && currentPart !== null && typeof prevAstPart === 'object' && prevAstPart !== null) {\n      if (\n        currentPart.type === 'variable' &&\n        prevAstPart.type === 'variable' &&\n        currentPart.bracketsGroup == prevAstPart.bracketsGroup\n      ) {\n        if (currentPart.name === 'plural' || currentPart.name === 'selectordinal' || currentPart.name === 'select') {\n          scopeVariableName = prevAstPart.name;\n          currentPart = {\n            type: currentPart.name === 'select' ? 'select' : 'plural',\n            cardinal: currentPart.name !== 'selectordinal',\n            variable: prevAstPart,\n            options: {},\n          } as PluralNode | SelectNode;\n          ast.pop();\n        } else if (externals.includes(currentPart.name)) {\n          currentPart = {\n            type: 'external',\n            name: currentPart.name,\n            variableName: prevAstPart.name,\n            data: null,\n            optionsPart: triggerChar !== '}',\n            rawData: '',\n          };\n          ast.pop();\n        } else {\n          throw new Error(`Unsupported syntax rule \"${currentPart.name}\"`);\n        }\n      }\n      if (currentPart.type === 'plural-offset' && prevAstPart.type === 'plural') {\n        partConsumed = true;\n        currentPart.value = Number.parseInt(currentPart.rawValue, 10);\n        prevAstPart.offset = currentPart;\n      }\n      if (currentPart.type === 'plural-exact-value' && prevAstPart.type === 'plural') {\n        partConsumed = true;\n        prevAstPart.options.exacts = prevAstPart.options.exacts ?? {};\n        prevAstPart.options.exacts[currentPart.value] = [];\n        parentAstChain.push(ast);\n        ast = prevAstPart.options.exacts[currentPart.value];\n      }\n      if (\n        currentPart.type === 'variable' &&\n        ((prevAstPart.type === 'plural' && pluralOptions.includes(currentPart.name)) || prevAstPart.type === 'select')\n      ) {\n        partConsumed = true;\n        prevAstPart.options[currentPart.name as keyof typeof prevAstPart.options] = [];\n        parentAstChain.push(ast);\n        ast = prevAstPart.options[currentPart.name as keyof typeof prevAstPart.options] as AstNode[];\n      }\n    }\n    if (!partConsumed && currentPart !== null) {\n      ast.push(currentPart);\n      prevAstPart = currentPart;\n    }\n    currentAstPart = null;\n  };\n\n  for (let i = 0; i < message.length; i++) {\n    const char = message[i];\n    const currentEscaping = escaping;\n    if (char === \"'\") {\n      escaping = !escaping;\n      nextPart(char);\n      if (message[i - 1] === \"'\") {\n        currentAstPart = { type: 'pure-text', text: \"'\" };\n        nextPart(char);\n      }\n      continue;\n    }\n    const prevDepth = depth;\n\n    if (char === '}' && !currentEscaping) {\n      if (depth <= 0) {\n        throw new Error(`Broken order of \"{\" and \"}\" in \"${message}\" of symbol ${i}`);\n      }\n      depth--;\n    }\n\n    if (char === '{' && !currentEscaping) {\n      depth++;\n      bracketsGroupChunkId++;\n    }\n\n    if (typeof prevAstPart === 'object' && prevAstPart?.type === 'external' && prevAstPart.optionsPart) {\n      if (prevDepth === depth) {\n        prevAstPart.rawData += char;\n      } else {\n        const verboseParsing =\n          prevAstPart.rawData.trim() === 'verbose' ? (options.verboseParsing ?? {})[prevAstPart.variableName] : undefined;\n        const parserAvailable = options.externalParsers?.[prevAstPart.name] || verboseParsing;\n        if (!parserAvailable) {\n          throw new Error(`Parser for \"${prevAstPart.name}\" (variable \"${prevAstPart.variableName}\") was not provided`);\n        }\n        prevAstPart.data = options.externalParsers?.[prevAstPart.name](\n          prevAstPart.rawData,\n          prevAstPart.variableName,\n          verboseParsing,\n        );\n        prevAstPart = null;\n      }\n      continue;\n    }\n\n    if (char === '#' && !currentEscaping && scopeVariableName) {\n      const parentAst = parentAstChain[parentAstChain.length - 1];\n      const parentNode = parentAst?.[parentAst?.length - 1];\n      if (typeof parentNode === 'object' && parentNode.type === 'plural') {\n        nextPart(char);\n\n        currentAstPart = {\n          type: 'external',\n          name: 'number',\n          optionsPart: false,\n          variableName: parentNode.variable.name,\n          data: { offset: parentNode.offset?.value },\n          rawData: '#',\n        };\n\n        nextPart(char);\n        continue;\n      }\n    }\n    const valueDepth = depth % 2 === 0;\n    if (prevDepth !== depth && currentAstPart !== null) {\n      nextPart(char);\n    }\n    if (!valueDepth && prevDepth > depth && parentAstChain.length > 0) {\n      ast = parentAstChain.pop()!;\n      prevAstPart = ast[ast.length - 1];\n    }\n    if (prevDepth !== depth) continue;\n\n    if (currentAstPart === null) {\n      if (currentEscaping) {\n        currentAstPart = { type: 'pure-text', text: '' };\n      } else if (valueDepth) currentAstPart = '';\n      else if (char === ' ') continue;\n      else if (char === '\\n') continue;\n      else if (char === '\\r') continue;\n      else if (char === '\\t') continue;\n      else if (char === '=') {\n        currentAstPart = { type: 'plural-exact-value', value: '' } as AstNode;\n        continue;\n      } else {\n        currentAstPart = {\n          type: 'variable',\n          name: '',\n          bracketsGroup: bracketsGroupChunkId,\n        } as AstNode;\n      }\n    }\n    if (typeof currentAstPart === 'object' && currentAstPart !== null && (char === ',' || char === ' ') && !currentEscaping) {\n      nextPart(char);\n    }\n    if (currentAstPart === null) {\n      if (valueDepth) currentAstPart = '';\n    }\n\n    if (typeof currentAstPart === 'string') currentAstPart += char;\n    if (typeof currentAstPart === 'object' && currentAstPart !== null) {\n      if (currentAstPart.type === 'pure-text') currentAstPart.text += char;\n      if (currentAstPart.type === 'plural-exact-value') currentAstPart.value += char;\n      if (currentAstPart.type === 'plural-offset') currentAstPart.rawValue += char;\n      if (currentAstPart.type === 'variable') {\n        if (char === ':' && currentAstPart.name === 'offset') {\n          currentAstPart = { type: 'plural-offset', rawValue: '', value: 0 };\n        } else {\n          currentAstPart.name += char;\n        }\n      }\n    }\n  }\n  if (depth > 0) {\n    throw new Error(`Broken order of \"{\" and \"}\" in \"${message}\" (need ${depth} more \"}\")`);\n  }\n  if (depth < 0) {\n    throw new Error(`Broken order of \"{\" and \"}\" in \"${message}\" (${depth * -1} \"}\" is/are extra)`);\n  }\n  while (parentAstChain.length > 0) {\n    ast = parentAstChain.pop()!;\n  }\n  if (currentAstPart !== null) ast.push(currentAstPart);\n\n  return runPostParsers(ast, options.postParsers);\n};\n\nexport type PostParser<InputAst extends AstNode[], OutputAst extends AstNode[]> = (inputAst: InputAst) => OutputAst;\n"],"names":["pluralOptions","externals","runPostParsers","ast","postParsers","reduce","postParser","message","options","includes","parentAstChain","scopeVariableName","prevAstPart","currentAstPart","escaping","depth","bracketsGroupChunkId","nextPart","triggerChar","currentPart","partConsumed","type","bracketsGroup","name","cardinal","variable","pop","variableName","data","optionsPart","rawData","value","Number","parseInt","rawValue","offset","exacts","_prevAstPart$options$","push","i","length","_prevAstPart","_char","currentEscaping","char","prevDepth","Error","_options$verboseParsi","_options$externalPars","_options$externalPars2","trim","verboseParsing","undefined","externalParsers","parentAst","parentNode","_parentNode$offset","valueDepth","text"],"mappings":"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"}