{
  "version": 3,
  "sources": ["../../../../../src/functions/logical/if/if.ts"],
  "sourcesContent": [
    "import {\n  FormulaError,\n  type CellAddress,\n  type CellValue,\n  type ErrorEvaluationResult,\n  type FunctionDefinition,\n  type FunctionEvaluationResult,\n  type SingleEvaluationResult,\n  type SpilledValuesEvaluationResult,\n  type SpreadsheetRange\n} from \"../../../core/types.mjs\";\nimport type { EvaluationContext } from \"../../../evaluator/evaluation-context.mjs\";\nimport type { FormulaEvaluator } from \"../../../evaluator/formula-evaluator.mjs\";\n\n/**\n * IF function - Returns one value if a condition is true and another value if it's false\n *\n * Usage: IF(logical_test, value_if_true, [value_if_false])\n *\n * logical_test: The condition to evaluate (required)\n * value_if_true: The value to return if the condition is true (required)\n * value_if_false: The value to return if the condition is false (optional, defaults to FALSE)\n *\n * Examples:\n *   IF(A1>10, \"High\", \"Low\") - returns \"High\" if A1>10, otherwise \"Low\"\n *   IF(B1=\"\", \"Empty\", B1) - returns \"Empty\" if B1 is empty, otherwise B1's value\n *   IF(C1<0, \"Negative\") - returns \"Negative\" if C1<0, otherwise FALSE\n *\n * Note:\n * - Supports spilled values (dynamic arrays) for all arguments\n * - Logical test evaluation: 0 and empty string are FALSE, everything else is TRUE\n * - If logical_test is spilled, returns spilled results\n */\n\n/**\n * Convert a cell value to boolean for logical evaluation\n */\nfunction isTruthy(value: CellValue): boolean {\n  switch (value.type) {\n    case \"boolean\":\n      return value.value;\n    case \"number\":\n      return value.value !== 0;\n    case \"string\":\n      return value.value !== \"\";\n    case \"infinity\":\n      return true; // Infinity is truthy\n    default:\n      return false;\n  }\n}\n\n/**\n * Helper for creating spilled-values result for IF function\n */\nfunction createIfSpilledResult(\n  this: FormulaEvaluator,\n  {\n    logicalTestResult,\n    valueIfTrueResult,\n    valueIfFalseResult,\n    context,\n  }: {\n    logicalTestResult: FunctionEvaluationResult;\n    valueIfTrueResult: FunctionEvaluationResult;\n    valueIfFalseResult: FunctionEvaluationResult;\n    context: EvaluationContext;\n  }\n): SpilledValuesEvaluationResult | ErrorEvaluationResult {\n  const hasSpilledTest = logicalTestResult.type === \"spilled-values\";\n  const hasSpilledTrue = valueIfTrueResult.type === \"spilled-values\";\n  const hasSpilledFalse = valueIfFalseResult.type === \"spilled-values\";\n\n  if (!hasSpilledTest && !hasSpilledTrue && !hasSpilledFalse) {\n    throw new Error(\"createIfSpilledResult called without spilled values\");\n  }\n\n  return {\n    type: \"spilled-values\",\n    spillArea: (origin: CellAddress): SpreadsheetRange => {\n      // Calculate spill area (union of all spilled ranges)\n      let spillArea: SpreadsheetRange | undefined;\n\n      const spilledResults = [\n        hasSpilledTest ? logicalTestResult : null,\n        hasSpilledTrue ? valueIfTrueResult : null,\n        hasSpilledFalse ? valueIfFalseResult : null,\n      ].filter(Boolean) as SpilledValuesEvaluationResult[];\n\n      for (const result of spilledResults) {\n        const currentSpillArea = result.spillArea(origin);\n        if (!spillArea) {\n          spillArea = currentSpillArea;\n        } else {\n          spillArea = this.unionRanges(\n            this.projectRange(spillArea, origin),\n            this.projectRange(currentSpillArea, origin)\n          );\n        }\n      }\n\n      if (!spillArea) {\n        throw new Error(\"No spilled values found\");\n      }\n      return spillArea;\n    },\n    source: \"IF with spilled values\",\n    evaluate: (spilledCell: any, evalContext: any): SingleEvaluationResult => {\n      // Evaluate all arguments at this spilled position\n      const spillLogicalResult = hasSpilledTest\n        ? logicalTestResult.evaluate(spilledCell, evalContext)\n        : logicalTestResult;\n      const spillTrueResult = hasSpilledTrue\n        ? valueIfTrueResult.evaluate(spilledCell, evalContext)\n        : valueIfTrueResult;\n      const spillFalseResult = hasSpilledFalse\n        ? valueIfFalseResult.evaluate(spilledCell, evalContext)\n        : valueIfFalseResult;\n\n      // Check for errors\n      if (spillLogicalResult === undefined) {\n        return {\n          type: \"error\",\n          err: FormulaError.REF,\n          message: \"The spilled logical test has not been evaluated\",\n          errAddress: context.dependencyNode,\n        };\n      }\n      if (spillLogicalResult.type === \"error\" || spillLogicalResult.type === \"awaiting-evaluation\") {\n        return spillLogicalResult;\n      }\n\n      if (spillTrueResult === undefined) {\n        return {\n          type: \"error\",\n          err: FormulaError.REF,\n          message: \"The spilled true value has not been evaluated\",\n          errAddress: context.dependencyNode,\n        };\n      }\n      if (spillTrueResult.type === \"error\" || spillTrueResult.type === \"awaiting-evaluation\") {\n        return spillTrueResult;\n      }\n\n      if (spillFalseResult === undefined) {\n        return {\n          type: \"error\",\n          err: FormulaError.REF,\n          message: \"The spilled false value has not been evaluated\",\n          errAddress: context.dependencyNode,\n        };\n      }\n      if (spillFalseResult.type === \"error\" || spillFalseResult.type === \"awaiting-evaluation\") {\n        return spillFalseResult;\n      }\n\n      // Perform IF logic\n      if (spillLogicalResult.type !== \"value\") {\n        return {\n          type: \"error\",\n          err: FormulaError.VALUE,\n          message: \"Invalid logical test result\",\n          errAddress: context.dependencyNode,\n        };\n      }\n\n      const isTrue = isTruthy(spillLogicalResult.result);\n      return isTrue ? spillTrueResult : spillFalseResult;\n    },\n    evaluateAllCells: (intersectingRange: any) => {\n      throw new Error(\"WIP: evaluateAllCells for IF is not implemented\");\n    },\n  };\n}\n\n/**\n * IF function implementation\n */\nexport const IF: FunctionDefinition = {\n  name: \"IF\",\n  evaluate: function (node, context): FunctionEvaluationResult {\n    if (node.args.length < 2 || node.args.length > 3) {\n      return {\n        type: \"error\",\n        err: FormulaError.VALUE,\n        message: \"IF function takes 2 or 3 arguments\",\n        errAddress: context.dependencyNode,\n      };\n    }\n\n    // Evaluate logical test\n    const logicalTestResult = this.evaluateNode(node.args[0]!, context);\n    if (\n      logicalTestResult.type === \"awaiting-evaluation\" ||\n      logicalTestResult.type === \"error\"\n    ) {\n      return logicalTestResult;\n    }\n\n    // Handle spilled values - we need to evaluate both branches\n    // because different cells might take different paths\n    if (logicalTestResult.type === \"spilled-values\") {\n      // Evaluate value_if_true\n      const valueIfTrueResult = this.evaluateNode(node.args[1]!, context);\n      if (valueIfTrueResult.type === \"error\" || valueIfTrueResult.type === \"awaiting-evaluation\") {\n        return valueIfTrueResult;\n      }\n\n      // Evaluate value_if_false (optional, defaults to FALSE)\n      let valueIfFalseResult: FunctionEvaluationResult;\n      if (node.args.length > 2) {\n        valueIfFalseResult = this.evaluateNode(node.args[2]!, context);\n        if (valueIfFalseResult.type === \"error\" || valueIfFalseResult.type === \"awaiting-evaluation\") {\n          return valueIfFalseResult;\n        }\n      } else {\n        valueIfFalseResult = {\n          type: \"value\",\n          result: { type: \"boolean\", value: false },\n        };\n      }\n\n      return createIfSpilledResult.call(this, {\n        logicalTestResult,\n        valueIfTrueResult,\n        valueIfFalseResult,\n        context,\n      });\n    }\n\n    // Evaluate the logical test\n    const isTrue = isTruthy(logicalTestResult.result);\n\n    // LAZY EVALUATION: Only evaluate the branch we need\n    if (isTrue) {\n      // Evaluate value_if_true\n      const valueIfTrueResult = this.evaluateNode(node.args[1]!, context);\n      return valueIfTrueResult;\n    } else {\n      // Evaluate value_if_false (optional, defaults to FALSE)\n      if (node.args.length > 2) {\n        const valueIfFalseResult = this.evaluateNode(node.args[2]!, context);\n        return valueIfFalseResult;\n      } else {\n        return {\n          type: \"value\",\n          result: { type: \"boolean\", value: false },\n        };\n      }\n    }\n  },\n};\n"
  ],
  "mappings": "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",
  "debugId": "8082D7E46D5CD04064756E2164756E21",
  "names": []
}