1use crate::{
2 phlow::PipelineMap,
3 pipeline::Pipeline,
4 step_worker::{StepReference, StepWorker, StepWorkerError},
5};
6use phlow_sdk::{prelude::*, valu3};
7use rhai::Engine;
8use std::sync::Arc;
9use std::{collections::HashMap, fmt::Display};
10use valu3::{traits::ToValueBehavior, value::Value};
11
12#[derive(Debug)]
13pub enum TransformError {
14 InnerStepError(StepWorkerError),
15 Parser(valu3::Error),
16}
17
18impl Display for TransformError {
19 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20 match self {
21 TransformError::InnerStepError(err) => write!(f, "Inner step error: {}", err),
22 TransformError::Parser(_) => write!(f, "Parser error: Non parseable"),
23 }
24 }
25}
26
27pub(crate) fn value_to_pipelines(
28 engine: Arc<Engine>,
29 modules: Arc<Modules>,
30 input: &Value,
31) -> Result<PipelineMap, TransformError> {
32 let mut map = Vec::new();
33
34 process_raw_steps(input, &mut map);
35 value_to_structs(engine, modules, &map)
36}
37
38pub(crate) fn process_raw_steps(input: &Value, map: &mut Vec<Value>) -> Value {
39 if let Value::Object(pipeline) = input {
40 let mut new_pipeline = pipeline.clone();
41
42 new_pipeline.remove(&"steps");
43
44 if let Some(then) = pipeline.get("then") {
46 let then_value = process_raw_steps(then, map);
47 new_pipeline.insert("then".to_string(), then_value);
48 }
49
50 if let Some(els) = pipeline.get("else") {
52 let else_value = process_raw_steps(els, map);
53 new_pipeline.insert("else".to_string(), else_value);
54 }
55
56 let mut new_steps = if new_pipeline.is_empty() {
57 vec![]
58 } else {
59 vec![new_pipeline.to_value()]
60 };
61
62 if let Some(steps) = pipeline.get("steps") {
63 if let Value::Array(steps) = steps {
64 for step in steps {
65 let mut new_step = step.clone();
66
67 if let Some(then) = step.get("then") {
68 new_step.insert("then".to_string(), process_raw_steps(then, map));
69 }
70
71 if let Some(els) = step.get("else") {
72 new_step.insert("else".to_string(), process_raw_steps(els, map));
73 }
74
75 new_steps.push(new_step);
76 }
77 }
78 }
79
80 map.push(new_steps.to_value());
81 } else if let Value::Array(pipeline) = input {
82 let mut new_steps = Vec::new();
83
84 for step in pipeline {
85 if let Value::Object(step) = step {
86 let mut new_step = step.clone();
87
88 if let Some(then) = step.get("then") {
89 new_step.insert("then".to_string(), process_raw_steps(then, map));
90 }
91
92 if let Some(els) = step.get("else") {
93 new_step.insert("else".to_string(), process_raw_steps(els, map));
94 }
95
96 new_steps.push(new_step);
97 }
98 }
99
100 map.push(new_steps.to_value());
101 }
102
103 (map.len() - 1).to_value()
104}
105
106fn value_to_structs(
112 engine: Arc<Engine>,
113 modules: Arc<Modules>,
114 pipelines_raw: &Vec<Value>,
115) -> Result<PipelineMap, TransformError> {
116 let (parents, go_to_step_id) = map_parents(pipelines_raw);
117 let mut pipelines = HashMap::new();
118
119 for (pipeline_index, pipeline_value) in pipelines_raw.iter().enumerate() {
120 if let Value::Array(arr) = pipeline_value {
121 let mut steps = Vec::new();
122
123 for (step_index, step_value) in arr.into_iter().enumerate() {
124 if let Value::Object(step) = step_value {
125 let mut new_step = step.clone();
126
127 if let Some(to) = step.get("to") {
128 if let Some(go_to_step) = go_to_step_id.get(to.to_string().as_str()) {
129 new_step.insert("to".to_string(), go_to_step.to_value());
130 }
131 } else {
132 if step.get("then").is_none()
133 && step.get("else").is_none()
134 && step.get("return").is_none()
135 {
136 if let Some(target) = parents.get(&StepReference {
137 pipeline: pipeline_index,
138 step: step_index,
139 }) {
140 let next_step = get_next_step(&pipelines_raw, target);
141 new_step.insert("to".to_string(), next_step.to_value());
142 }
143 }
144 }
145
146 let step_worker = StepWorker::try_from_value(
147 engine.clone(),
148 modules.clone(),
149 &new_step.to_value(),
150 )
151 .map_err(TransformError::InnerStepError)?;
152 steps.push(step_worker);
153 }
154 }
155
156 pipelines.insert(pipeline_index, Pipeline { steps });
157 }
158 }
159
160 Ok(pipelines)
161}
162
163fn get_next_step(pipelines: &Vec<Value>, target: &StepReference) -> StepReference {
166 if let Value::Array(arr) = &pipelines[target.pipeline] {
167 let next_step_index = target.step + 1;
168 if arr.get(next_step_index).is_some() {
169 return StepReference {
170 pipeline: target.pipeline,
171 step: next_step_index,
172 };
173 }
174 }
175
176 return StepReference {
177 pipeline: target.pipeline,
178 step: target.step,
179 };
180}
181
182fn map_parents(
185 pipelines: &Vec<Value>,
186) -> (
187 HashMap<StepReference, StepReference>,
188 HashMap<String, StepReference>,
189) {
190 let (parents, go_to_step_references) = build_parent_map(pipelines);
191 (resolve_final_parents(parents), go_to_step_references)
192}
193
194fn build_parent_map(
198 pipelines: &Vec<Value>,
199) -> (
200 HashMap<StepReference, StepReference>,
201 HashMap<String, StepReference>,
202) {
203 let mut parents = HashMap::new();
204 let mut go_to_step_id = HashMap::new();
205
206 for (pipeline_index, steps) in pipelines.iter().enumerate() {
207 if let Value::Array(arr) = steps {
208 for (step_index, step) in arr.into_iter().enumerate() {
209 if let Value::Object(step) = step {
210 if let Some(id) = step.get("id") {
211 go_to_step_id.insert(
212 id.to_string(),
213 StepReference {
214 pipeline: pipeline_index,
215 step: step_index,
216 },
217 );
218 }
219
220 if let Some(then_value) = step.get("then").and_then(|v| v.to_u64()) {
222 parents.insert(
223 StepReference {
224 pipeline: then_value as usize,
225 step: 0,
226 },
227 StepReference {
228 pipeline: pipeline_index,
229 step: step_index,
230 },
231 );
232 }
233
234 if let Some(else_value) = step.get("else").and_then(|v| v.to_u64()) {
235 parents.insert(
236 StepReference {
237 pipeline: else_value as usize,
238 step: 0,
239 },
240 StepReference {
241 pipeline: pipeline_index,
242 step: step_index,
243 },
244 );
245 }
246 }
247 }
248 }
249 }
250
251 (parents, go_to_step_id)
252}
253
254fn resolve_final_parents(
257 parents: HashMap<StepReference, StepReference>,
258) -> HashMap<StepReference, StepReference> {
259 let mut final_parents = HashMap::new();
260
261 for (child, mut parent) in parents.iter() {
262 while let Some(grandparent) = parents.get(parent) {
264 parent = grandparent;
265 }
266 final_parents.insert(child.clone(), parent.clone());
267 }
268
269 final_parents
270}