Spaces:
Sleeping
Sleeping
File size: 5,764 Bytes
05c5ed5 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 | import { safe } from "ts-safe";
import { OutputSchemaSourceKey } from "./workflow.interface";
/**
* Condition operators for string-based comparisons.
* Used to evaluate string values from node outputs.
*/
export enum StringConditionOperator {
Equals = "equals",
NotEquals = "not_equals",
Contains = "contains",
NotContains = "not_contains",
StartsWith = "starts_with",
EndsWith = "ends_with",
IsEmpty = "is_empty",
IsNotEmpty = "is_not_empty",
}
/**
* Condition operators for number-based comparisons.
* Inherits string equality operators and adds numeric comparisons.
*/
export enum NumberConditionOperator {
Equals = StringConditionOperator.Equals,
NotEquals = StringConditionOperator.NotEquals,
GreaterThan = "greater_than",
LessThan = "less_than",
GreaterThanOrEqual = "greater_than_or_equal",
LessThanOrEqual = "less_than_or_equal",
}
/**
* Condition operators for boolean value testing.
*/
export enum BooleanConditionOperator {
IsTrue = "is_true",
IsFalse = "is_false",
}
/**
* Gets the default condition operator for a given data type.
* Used when creating new conditions in the UI.
*/
export function getFirstConditionOperator(
type: "string" | "number" | "boolean",
) {
switch (type) {
case "string":
return StringConditionOperator.Equals;
case "number":
return NumberConditionOperator.Equals;
case "boolean":
return BooleanConditionOperator.IsTrue;
default:
return StringConditionOperator.Equals;
}
}
/**
* Union type of all possible condition operators.
*/
export type ConditionOperator =
| StringConditionOperator
| NumberConditionOperator
| BooleanConditionOperator;
/**
* A single condition rule that compares a value from a node output
* with a target value using a specified operator.
*/
export type ConditionRule = {
source: OutputSchemaSourceKey; // Reference to another node's output field
operator: ConditionOperator;
value?: string | number | boolean; // Comparison value (not needed for is_empty, is_not_empty, is_true, is_false)
};
/**
* A condition branch for if-elseIf-else structure.
* Each branch can have multiple conditions combined with AND/OR logic.
*/
export type ConditionBranch = {
id: "if" | "else" | (string & {});
type: "if" | "elseIf" | "else";
conditions: ConditionRule[]; // Not needed for 'else' type
logicalOperator: "AND" | "OR"; // How to combine multiple conditions, not needed for 'else'
};
/**
* Complete condition structure supporting if-elseIf-else branching.
* Used by Condition nodes to determine execution flow.
*/
export type ConditionBranches = {
if: ConditionBranch;
elseIf?: ConditionBranch[]; // Optional multiple elseIf branches
else: ConditionBranch; // Optional else branch
};
/**
* Evaluates a condition branch to determine if it should be executed.
*
* @param branch - The condition branch to evaluate
* @param getSourceValue - Function to get values from node outputs
* @returns True if the branch conditions are met
*/
export function checkConditionBranch(
branch: ConditionBranch,
getSourceValue: (
source: OutputSchemaSourceKey,
) => string | number | boolean | undefined,
): boolean {
// Evaluate all conditions in the branch
const results = branch.conditions?.map((condition) => {
return checkConditionRule({
operator: condition.operator,
target: String(condition.value || ""),
source: getSourceValue(condition.source),
});
}) ?? [false];
// Combine results based on logical operator
if (branch.logicalOperator === "AND") {
return results.every((result) => result);
}
return results.some((result) => result);
}
/**
* Evaluates a single condition rule.
*
* @param params - The condition rule parameters
* @returns True if the condition is met
*/
function checkConditionRule({
operator,
target,
source,
}: {
operator: ConditionOperator;
target: string;
source?: string | number | boolean;
}): boolean {
return safe(() => {
switch (operator) {
case StringConditionOperator.Equals:
if (source == target) return true;
break;
case StringConditionOperator.NotEquals:
if (source != target) return true;
break;
case StringConditionOperator.Contains:
if (String(source).includes(String(target))) return true;
break;
case StringConditionOperator.NotContains:
if (!String(source).includes(String(target))) return true;
break;
case StringConditionOperator.StartsWith:
if (String(source).startsWith(String(target))) return true;
break;
case StringConditionOperator.EndsWith:
if (String(source).endsWith(String(target))) return true;
break;
case StringConditionOperator.IsEmpty:
if (!source) return true;
break;
case StringConditionOperator.IsNotEmpty:
if (source) return true;
break;
case NumberConditionOperator.GreaterThan:
if (Number(source) > Number(target)) return true;
break;
case NumberConditionOperator.LessThan:
if (Number(source) < Number(target)) return true;
break;
case NumberConditionOperator.GreaterThanOrEqual:
if (Number(source) >= Number(target)) return true;
break;
case NumberConditionOperator.LessThanOrEqual:
if (Number(source) <= Number(target)) return true;
break;
case BooleanConditionOperator.IsTrue:
if (source) return true;
break;
case BooleanConditionOperator.IsFalse:
if (!source) return true;
break;
}
return false;
})
.ifFail((e) => {
console.error("Condition evaluation error:", e);
return false;
})
.unwrap();
}
|