fix(canvas): reject invalid edge splits before mutation
This commit is contained in:
76
components/canvas/canvas-connection-validation.ts
Normal file
76
components/canvas/canvas-connection-validation.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import type { Connection, Edge as RFEdge, Node as RFNode } from "@xyflow/react";
|
||||
|
||||
import {
|
||||
validateCanvasConnectionPolicy,
|
||||
type CanvasConnectionValidationReason,
|
||||
} from "@/lib/canvas-connection-policy";
|
||||
|
||||
export function validateCanvasConnection(
|
||||
connection: Connection,
|
||||
nodes: RFNode[],
|
||||
edges: RFEdge[],
|
||||
edgeToReplaceId?: string,
|
||||
): CanvasConnectionValidationReason | null {
|
||||
if (!connection.source || !connection.target) return "incomplete";
|
||||
if (connection.source === connection.target) return "self-loop";
|
||||
|
||||
const sourceNode = nodes.find((node) => node.id === connection.source);
|
||||
const targetNode = nodes.find((node) => node.id === connection.target);
|
||||
if (!sourceNode || !targetNode) return "unknown-node";
|
||||
|
||||
return validateCanvasConnectionByType({
|
||||
sourceType: sourceNode.type ?? "",
|
||||
targetType: targetNode.type ?? "",
|
||||
targetNodeId: connection.target,
|
||||
edges,
|
||||
edgeToReplaceId,
|
||||
});
|
||||
}
|
||||
|
||||
export function validateCanvasConnectionByType(args: {
|
||||
sourceType: string;
|
||||
targetType: string;
|
||||
targetNodeId: string;
|
||||
edges: RFEdge[];
|
||||
edgeToReplaceId?: string;
|
||||
}): CanvasConnectionValidationReason | null {
|
||||
const targetIncomingCount = args.edges.filter(
|
||||
(edge) => edge.target === args.targetNodeId && edge.id !== args.edgeToReplaceId,
|
||||
).length;
|
||||
|
||||
return validateCanvasConnectionPolicy({
|
||||
sourceType: args.sourceType,
|
||||
targetType: args.targetType,
|
||||
targetIncomingCount,
|
||||
});
|
||||
}
|
||||
|
||||
export function validateCanvasEdgeSplit(args: {
|
||||
nodes: RFNode[];
|
||||
edges: RFEdge[];
|
||||
splitEdge: RFEdge;
|
||||
middleNode: RFNode;
|
||||
}): CanvasConnectionValidationReason | null {
|
||||
const sourceNode = args.nodes.find((node) => node.id === args.splitEdge.source);
|
||||
const targetNode = args.nodes.find((node) => node.id === args.splitEdge.target);
|
||||
|
||||
if (!sourceNode || !targetNode) {
|
||||
return "unknown-node";
|
||||
}
|
||||
|
||||
return (
|
||||
validateCanvasConnectionByType({
|
||||
sourceType: sourceNode.type ?? "",
|
||||
targetType: args.middleNode.type ?? "",
|
||||
targetNodeId: args.middleNode.id,
|
||||
edges: args.edges,
|
||||
}) ??
|
||||
validateCanvasConnectionByType({
|
||||
sourceType: args.middleNode.type ?? "",
|
||||
targetType: targetNode.type ?? "",
|
||||
targetNodeId: targetNode.id,
|
||||
edges: args.edges,
|
||||
edgeToReplaceId: args.splitEdge.id,
|
||||
})
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user