@vaudience/aigentflow-flow-validator 0.23.0 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/PARITY.md +16 -0
- package/dist/cli.js +70 -20
- package/dist/index.cjs +70 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +70 -20
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2631,31 +2631,81 @@ function validateConnectivity(flow, issues) {
|
|
|
2631
2631
|
});
|
|
2632
2632
|
}
|
|
2633
2633
|
}
|
|
2634
|
-
|
|
2635
|
-
const recStack = /* @__PURE__ */ new Set();
|
|
2636
|
-
const hasCycle = (stepID) => {
|
|
2637
|
-
if (recStack.has(stepID)) return true;
|
|
2638
|
-
if (visited.has(stepID)) return false;
|
|
2639
|
-
visited.add(stepID);
|
|
2640
|
-
recStack.add(stepID);
|
|
2641
|
-
const step = steps[stepID];
|
|
2642
|
-
if (isRecord(step) && isRecord(step.next)) {
|
|
2643
|
-
const next = step.next;
|
|
2644
|
-
for (const target of cycleTargets(next, `steps.${stepID}.next`, issues)) {
|
|
2645
|
-
if (hasCycle(target)) return true;
|
|
2646
|
-
}
|
|
2647
|
-
}
|
|
2648
|
-
recStack.delete(stepID);
|
|
2649
|
-
return false;
|
|
2650
|
-
};
|
|
2651
|
-
if (hasCycle(start)) {
|
|
2634
|
+
if (cycleWithoutExit(steps, start, issues)) {
|
|
2652
2635
|
issues.warn({
|
|
2653
2636
|
field: "steps",
|
|
2654
|
-
message: "Potential infinite loop detected in step flow",
|
|
2637
|
+
message: "Potential infinite loop detected in step flow: a cycle of steps has no way out",
|
|
2655
2638
|
code: "potential_infinite_loop",
|
|
2656
|
-
suggestion: "
|
|
2639
|
+
suggestion: "Give one step in the cycle a `next.conditions` branch that leaves it (or end the flow there)"
|
|
2640
|
+
});
|
|
2641
|
+
}
|
|
2642
|
+
}
|
|
2643
|
+
function cycleEdges(step, stepID, issues) {
|
|
2644
|
+
if (!isRecord(step) || !isRecord(step.next)) return [];
|
|
2645
|
+
const next = step.next;
|
|
2646
|
+
const nextPath = `steps.${stepID}.next`;
|
|
2647
|
+
const out = [];
|
|
2648
|
+
const def = issues.stringOf(next, "default", nextPath);
|
|
2649
|
+
if (def !== null && def !== "") out.push(def);
|
|
2650
|
+
if (Array.isArray(next.conditions)) {
|
|
2651
|
+
next.conditions.forEach((cond, i) => {
|
|
2652
|
+
if (!isRecord(cond)) return;
|
|
2653
|
+
const goto = issues.stringOf(cond, "goto", `${nextPath}.conditions[${i}]`);
|
|
2654
|
+
if (goto !== null && goto !== "") out.push(goto);
|
|
2657
2655
|
});
|
|
2658
2656
|
}
|
|
2657
|
+
return out;
|
|
2658
|
+
}
|
|
2659
|
+
function stepLeavesCycle(steps, stepID, inCycle, issues) {
|
|
2660
|
+
const step = steps[stepID];
|
|
2661
|
+
if (!isRecord(step) || !isRecord(step.next)) return true;
|
|
2662
|
+
const next = step.next;
|
|
2663
|
+
if (next.parallel !== void 0 && next.parallel !== null) return true;
|
|
2664
|
+
const def = issues.stringOf(next, "default", `steps.${stepID}.next`);
|
|
2665
|
+
if (def === null || def === "") return true;
|
|
2666
|
+
for (const target of cycleEdges(step, stepID, issues)) {
|
|
2667
|
+
if (isMarker(target) || !inCycle.has(target)) return true;
|
|
2668
|
+
}
|
|
2669
|
+
return false;
|
|
2670
|
+
}
|
|
2671
|
+
function cycleWithoutExit(steps, start, issues) {
|
|
2672
|
+
let index = 0;
|
|
2673
|
+
const indices = /* @__PURE__ */ new Map();
|
|
2674
|
+
const low = /* @__PURE__ */ new Map();
|
|
2675
|
+
const onStack = /* @__PURE__ */ new Set();
|
|
2676
|
+
const stack = [];
|
|
2677
|
+
let found = false;
|
|
2678
|
+
const strong = (id) => {
|
|
2679
|
+
indices.set(id, index);
|
|
2680
|
+
low.set(id, index);
|
|
2681
|
+
index++;
|
|
2682
|
+
stack.push(id);
|
|
2683
|
+
onStack.add(id);
|
|
2684
|
+
for (const target of cycleEdges(steps[id], id, issues)) {
|
|
2685
|
+
if (isMarker(target) || !Object.prototype.hasOwnProperty.call(steps, target)) continue;
|
|
2686
|
+
if (!indices.has(target)) {
|
|
2687
|
+
strong(target);
|
|
2688
|
+
low.set(id, Math.min(low.get(id), low.get(target)));
|
|
2689
|
+
} else if (onStack.has(target)) {
|
|
2690
|
+
low.set(id, Math.min(low.get(id), indices.get(target)));
|
|
2691
|
+
}
|
|
2692
|
+
}
|
|
2693
|
+
if (low.get(id) !== indices.get(id)) return;
|
|
2694
|
+
const component = [];
|
|
2695
|
+
for (; ; ) {
|
|
2696
|
+
const top = stack.pop();
|
|
2697
|
+
onStack.delete(top);
|
|
2698
|
+
component.push(top);
|
|
2699
|
+
if (top === id) break;
|
|
2700
|
+
}
|
|
2701
|
+
const inCycle = new Set(component);
|
|
2702
|
+
const cyclic = component.length > 1 || cycleEdges(steps[id], id, issues).includes(id);
|
|
2703
|
+
if (!cyclic) return;
|
|
2704
|
+
if (component.some((member) => stepLeavesCycle(steps, member, inCycle, issues))) return;
|
|
2705
|
+
found = true;
|
|
2706
|
+
};
|
|
2707
|
+
if (Object.prototype.hasOwnProperty.call(steps, start)) strong(start);
|
|
2708
|
+
return found;
|
|
2659
2709
|
}
|
|
2660
2710
|
|
|
2661
2711
|
// src/validators/nextLogic.ts
|