{
  "version": 3,
  "sources": ["../../../../../src/functions/text/textjoin/textjoin.ts"],
  "sourcesContent": [
    "import {\n  FormulaError,\n  type CellValue,\n  type ErrorEvaluationResult,\n  type FunctionDefinition,\n  type FunctionEvaluationResult\n} from \"../../../core/types.mjs\";\nimport type { EvaluationContext } from \"../../../evaluator/evaluation-context.mjs\";\nimport type { FormulaEvaluator } from \"../../../evaluator/formula-evaluator.mjs\";\n\n/**\n * TEXTJOIN function - Joins text from multiple ranges and/or strings with a specified delimiter\n *\n * Usage: TEXTJOIN(delimiter, ignore_empty, text1, [text2], ...)\n *\n * delimiter: String to insert between text items (can be empty string \"\")\n * ignore_empty: If TRUE, empty cells/strings are ignored; if FALSE, they are included\n * text1, text2, ...: Text items to join (can be strings, ranges, or arrays)\n *\n * Examples:\n *   TEXTJOIN(\", \", TRUE, A1:A3) - joins A1, A2, A3 with \", \" separator, ignoring empty cells\n *   TEXTJOIN(\"-\", FALSE, \"a\", \"b\", \"c\") - returns \"a-b-c\"\n *   TEXTJOIN(\", \", TRUE, \"Red\", \"\", \"Blue\") - returns \"Red, Blue\" (empty string ignored)\n *\n * Note:\n * - Supports type coercion: numbers and booleans are converted to strings\n * - Returns #VALUE! if result exceeds 32,767 characters\n */\n\nconst MAX_TEXT_LENGTH = 32767;\n\n/**\n * Helper function to convert a cell value to string with type coercion\n */\nfunction coerceToString(value: CellValue): string {\n  switch (value.type) {\n    case \"string\":\n      return value.value;\n    case \"number\":\n      // Convert number to string\n      if (value.value === Infinity) {\n        return \"INFINITY\";\n      } else if (value.value === -Infinity) {\n        return \"-INFINITY\";\n      } else if (isNaN(value.value)) {\n        return \"NaN\";\n      } else {\n        return value.value.toString();\n      }\n    case \"boolean\":\n      // Convert boolean to string\n      return value.value ? \"TRUE\" : \"FALSE\";\n    case \"infinity\":\n      return value.sign === \"positive\" ? \"INFINITY\" : \"-INFINITY\";\n    default:\n      return \"\";\n  }\n}\n\n/**\n * Helper function to collect all text items from arguments, handling ranges\n */\nfunction collectTextItems(\n  this: FormulaEvaluator,\n  args: FunctionEvaluationResult[],\n  ignoreEmpty: boolean,\n  context: EvaluationContext\n): string[] | ErrorEvaluationResult {\n  const textItems: string[] = [];\n\n  for (const arg of args) {\n    if (arg.type === \"error\") {\n      return arg;\n    }\n\n    if (arg.type === \"value\") {\n      const text = coerceToString(arg.result);\n      if (!ignoreEmpty || text !== \"\") {\n        textItems.push(text);\n      }\n    } else if (arg.type === \"spilled-values\") {\n      // Extract all values from the range\n      const cellValues = arg.evaluateAllCells.call(this, {\n        context,\n        origin: context.cellAddress,\n        evaluate: arg.evaluate,\n        lookupOrder: \"col-major\",\n      });\n\n      if (cellValues.type !== \"values\") {\n        return cellValues;\n      }\n\n      for (const cellValue of cellValues.values) {\n        if (\n          cellValue.result.type === \"error\" ||\n          cellValue.result.type === \"awaiting-evaluation\"\n        ) {\n          return cellValue.result;\n        }\n        if (cellValue.result.type === \"value\") {\n          const text = coerceToString(cellValue.result.result);\n          if (!ignoreEmpty || text !== \"\") {\n            textItems.push(text);\n          }\n        }\n      }\n    }\n  }\n\n  return textItems;\n}\n\n/**\n * TEXTJOIN function implementation\n */\nexport const TEXTJOIN: FunctionDefinition = {\n  name: \"TEXTJOIN\",\n  evaluate: function (node, context): FunctionEvaluationResult {\n    if (node.args.length < 3) {\n      return {\n        type: \"error\",\n        err: FormulaError.VALUE,\n        message: \"TEXTJOIN function requires at least 3 arguments\",\n        errAddress: context.dependencyNode,\n      };\n    }\n\n    // Evaluate delimiter (first argument)\n    const delimiterResult = this.evaluateNode(node.args[0]!, context);\n    if (delimiterResult.type === \"error\") {\n      return delimiterResult;\n    }\n    if (delimiterResult.type === \"awaiting-evaluation\") {\n      return delimiterResult;\n    }\n\n    // Delimiter must be a single value\n    if (delimiterResult.type === \"spilled-values\") {\n      return {\n        type: \"error\",\n        err: FormulaError.VALUE,\n        message: \"TEXTJOIN delimiter must be a single value\",\n        errAddress: context.dependencyNode,\n      };\n    }\n\n    const delimiter = coerceToString(delimiterResult.result);\n\n    // Evaluate ignore_empty (second argument)\n    const ignoreEmptyResult = this.evaluateNode(node.args[1]!, context);\n    if (ignoreEmptyResult.type === \"error\") {\n      return ignoreEmptyResult;\n    }\n    if (ignoreEmptyResult.type === \"awaiting-evaluation\") {\n      return ignoreEmptyResult;\n    }\n\n    // ignore_empty must be a single value\n    if (ignoreEmptyResult.type === \"spilled-values\") {\n      return {\n        type: \"error\",\n        err: FormulaError.VALUE,\n        message: \"TEXTJOIN ignore_empty must be a single value\",\n        errAddress: context.dependencyNode,\n      };\n    }\n\n    // Convert ignore_empty to boolean\n    let ignoreEmpty = false;\n    if (ignoreEmptyResult.result.type === \"boolean\") {\n      ignoreEmpty = ignoreEmptyResult.result.value;\n    } else if (ignoreEmptyResult.result.type === \"number\") {\n      ignoreEmpty = ignoreEmptyResult.result.value !== 0;\n    } else if (ignoreEmptyResult.result.type === \"string\") {\n      ignoreEmpty = ignoreEmptyResult.result.value !== \"\";\n    }\n\n    // Evaluate text arguments (remaining arguments)\n    const textArgs: FunctionEvaluationResult[] = [];\n    for (let i = 2; i < node.args.length; i++) {\n      const result = this.evaluateNode(node.args[i]!, context);\n      if (result.type === \"error\" || result.type === \"awaiting-evaluation\") {\n        return result;\n      }\n      textArgs.push(result);\n    }\n\n    // Collect all text items from arguments\n    const textItems = collectTextItems.call(\n      this,\n      textArgs,\n      ignoreEmpty,\n      context\n    );\n\n    // Check if we got an error\n    if (!Array.isArray(textItems)) {\n      return textItems;\n    }\n\n    // Join text items with delimiter\n    const result = textItems.join(delimiter);\n\n    // Check length limit\n    if (result.length > MAX_TEXT_LENGTH) {\n      return {\n        type: \"error\",\n        err: FormulaError.VALUE,\n        message: `TEXTJOIN result exceeds ${MAX_TEXT_LENGTH} character limit`,\n        errAddress: context.dependencyNode,\n      };\n    }\n\n    return {\n      type: \"value\",\n      result: { type: \"string\", value: result },\n    };\n  },\n};\n"
  ],
  "mappings": "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",
  "debugId": "3B8102C5A2CC40FD64756E2164756E21",
  "names": []
}