1use wfrs_model::{
2 jsep::{BinaryExpression, JsepNode, MemberExpression},
3 json::JsonValue,
4 ConditionExpression,
5};
6use wfrs_model::{ExclusiveGatewayDef, WorkflowDefinition};
7
8pub struct Member<'a>(&'a MemberExpression);
9
10impl<'a> Member<'a> {
11 fn resolve<'v>(&self, mut variables: &'v JsonValue) -> &'v JsonValue {
12 if let JsepNode::Identifier(property) = self.0.property.as_ref() {
13 if let JsepNode::MemberExpression(member) = self.0.object.as_ref() {
14 variables = Member(member).resolve(variables);
15 if let Some(variables) = variables.as_object() {
16 if let Some(variables) = variables.get(property.name.as_ref()) {
17 return variables;
18 }
19 }
20 }
21 if let JsepNode::Identifier(object) = self.0.object.as_ref() {
22 if object.name.as_ref() == "$steps" {
23 if let Some(variables) = variables.as_object() {
24 if let Some(variables) = variables.get(property.name.as_ref()) {
25 return variables;
26 }
27 }
28 }
29 }
30 }
31 &JsonValue::Null
32 }
33}
34
35pub struct Value<'a>(&'a JsepNode);
36
37impl<'a> Value<'a> {
38 fn resolve<'v>(&self, variables: &'v JsonValue) -> &'v JsonValue
39 where
40 'a: 'v,
41 {
42 match self.0 {
43 JsepNode::MemberExpression(member) => Member(member).resolve(variables),
44 JsepNode::Literal(lit) => &lit.value,
45 _ => &JsonValue::Null,
46 }
47 }
48}
49
50pub struct Binary<'a>(&'a BinaryExpression);
51
52impl<'a> Binary<'a> {
53 pub fn validate(&self, variables: &JsonValue) -> bool {
54 let left = Value(&self.0.left).resolve(variables);
55 let right = Value(&self.0.right).resolve(variables);
56 match self.0.operator {
57 wfrs_model::jsep::Operator::Equal => left == right,
58 wfrs_model::jsep::Operator::NotEqual => left != right,
59 wfrs_model::jsep::Operator::Greater => {
60 if let Some((l, r)) = left.as_number().zip(right.as_number()) {
61 return l > r;
62 } else if let Some((l, r)) = left.as_str().zip(right.as_str()) {
63 return l > r;
64 } else if let Some((l, r)) = left.as_bool().zip(right.as_bool()) {
65 return l & !r;
66 }
67 false
68 }
69 wfrs_model::jsep::Operator::GreaterOrEqual => {
70 if let Some((l, r)) = left.as_number().zip(right.as_number()) {
71 return l >= r;
72 } else if let Some((l, r)) = left.as_str().zip(right.as_str()) {
73 return l >= r;
74 } else if let Some((l, r)) = left.as_bool().zip(right.as_bool()) {
75 return l >= r;
76 }
77 false
78 }
79 wfrs_model::jsep::Operator::Lower => {
80 if let Some((l, r)) = left.as_number().zip(right.as_number()) {
81 return l < r;
82 } else if let Some((l, r)) = left.as_str().zip(right.as_str()) {
83 return l < r;
84 } else if let Some((l, r)) = left.as_bool().zip(right.as_bool()) {
85 return !l & r;
86 }
87 false
88 }
89 wfrs_model::jsep::Operator::LowerOrEqual => {
90 if let Some((l, r)) = left.as_number().zip(right.as_number()) {
91 return l <= r;
92 } else if let Some((l, r)) = left.as_str().zip(right.as_str()) {
93 return l <= r;
94 } else if let Some((l, r)) = left.as_bool().zip(right.as_bool()) {
95 return l <= r;
96 }
97 false
98 }
99 wfrs_model::jsep::Operator::And => {
100 if let Some((l, r)) = left.as_bool().zip(right.as_bool()) {
101 if l && r {
102 return true;
103 }
104 }
105 false
106 }
107 wfrs_model::jsep::Operator::Or => {
108 if let Some(l) = left.as_bool() {
109 if l {
110 return true;
111 }
112 }
113 if let Some(r) = right.as_bool() {
114 if r {
115 return true;
116 }
117 }
118 false
119 }
120 }
121 }
122}
123
124pub struct Condition<'a>(pub &'a ConditionExpression);
125
126impl<'a> Condition<'a> {
127 pub fn validate(&self, variables: &JsonValue) -> bool {
128 match self.0 {
129 ConditionExpression::Jsep(node) => match node {
130 wfrs_model::jsep::JsepNode::BinaryExpression(binary_expr) => {
131 Binary(binary_expr).validate(variables)
132 }
133 _ => false,
134 },
135 }
136 }
137}
138
139pub struct ExclusiveGateway<'a>(pub &'a ExclusiveGatewayDef);
140
141impl<'a> ExclusiveGateway<'a> {
142 pub fn evaluate(&self, definition: &WorkflowDefinition, variables: &JsonValue) -> [i32; 1] {
143 let mut out = [self.0.default];
144 for outgoing in self.0.outgoing.iter() {
145 if let Some(expr) = definition
146 .flows
147 .get(*outgoing as usize)
148 .and_then(|f| f.condition_expression.as_ref())
149 {
150 if Condition(expr).validate(variables) {
151 out = [*outgoing];
152 break;
153 }
154 }
155 }
156 out
157 }
158}