All files / src/types commands.ts

75% Statements 9/12
100% Branches 0/0
50% Functions 3/6
75% Lines 9/12

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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                                                                                                                                                                                                                                                              33x 4x 33x 4x 33x 2x 33x   33x     33x      
// Base command interface
export interface BaseCommand {
  type: "ADD" | "MOVE" | "DELETE" | "CONNECT" | "DISCONNECT" | "MERGE_STREAMS";
  timestamp: number;
}
 
// Add command interface - NEW for tracking unit operation creation
export interface AddCommand extends BaseCommand {
  type: "ADD";
  objectId: number;
  graphicObjectId: number;
  objectType: string;
  serializedState: string; // Complete object data for recreation
  position: { x: number; y: number };
  groupId?: number;
}
 
// Move command interface
export interface MoveCommand extends BaseCommand {
  type: "MOVE";
  objectId: number;
  graphicObjectId: number;
  oldPosition: { x: number; y: number };
  newPosition: { x: number; y: number };
  groupObjects?: Array<{
    objectId: number;
    graphicObjectId: number;
    oldPosition: { x: number; y: number };
    newPosition: { x: number; y: number };
  }>;
}
 
// Delete command interface
export interface DeleteCommand extends BaseCommand {
  type: "DELETE";
  objects: Array<{
    id: number;
    objectType: string;
    serializedState: string;
  }>;
  connectionData?: Array<{
    portId: number;
    streamId: number | null;
    serializedConnection: string;
  }>;
}
 
// Connect command interface
export interface ConnectCommand extends BaseCommand {
  type: "CONNECT";
  connectionId?: string | number;
  portId1: number;
  objectId1: number;
  portId2: number;
  objectId2: number;
  streamId?: number;
  serializedConnection?: string;
  overwrittenConnections?: Array<{
    portId: number;
    oldStreamId: number | null;
    serializedOldConnection: string;
  }>;
}
 
// Disconnect command interface
export interface DisconnectCommand extends BaseCommand {
  type: "DISCONNECT";
  connectionId?: string | number;
  portId1: number;
  objectId1: number;
  portId2: number;
  objectId2: number;
  streamId?: number;
  serializedConnection: string;
  // Track split stream information
  wasSplitOperation?: boolean;
  originalStreamId?: number;
  newStreamIds?: number[]; // IDs of streams created during split
  portStreamMapping?: { [portId: number]: number }; // Which port got which new stream
}
 
// MergeStreams command interface - REDESIGNED for proper undo/redo
export interface MergeStreamsCommand extends BaseCommand {
  type: "MERGE_STREAMS";
 
  // Original stream information (before merge)
  stream1Id: number;
  stream1Data: string; // Serialized complete stream object
  stream2Id: number;
  stream2Data: string; // Serialized complete stream object
 
  // Port connection information (critical for undo)
  stream1PortConnections: string; // Serialized array of { portId, unitOpId, direction, key }
  stream2PortConnections: string; // Serialized array of { portId, unitOpId, direction, key }
 
  // Result information (what survived the merge)
  resultingStreamId: number; // The stream ID that remains after merge
  deletedStreamId: number; // The stream ID that was deleted during merge
 
  // Merge operation metadata
  stream1TypeWasFeed: boolean; // True if stream1 was a feed stream
  mergeType: "simple" | "intermediate" | "parallel" | "decision_node"; // Type of merge performed
 
  // Decision node information (if created)
  createdDecisionNodeId?: number;
  decisionNodeData?: string; // Serialized decision node if created
 
  // Graphic positioning for proper restoration
  stream1GraphicPositions: string; // Serialized graphic object positions
  stream2GraphicPositions: string; // Serialized graphic object positions
 
  // NEW FIELDS: track which of the original streams were deleted during the merge operation
  // This helps the undo path know which streams need to be recreated.
  stream1WasDeleted?: boolean;
  stream2WasDeleted?: boolean;
}
 
// Union type for all commands
export type Command =
  | AddCommand
  | MoveCommand
  | DeleteCommand
  | ConnectCommand
  | DisconnectCommand
  | MergeStreamsCommand;
 
// Type guard functions
export const isAddCommand = (command: Command): command is AddCommand =>
  command.type === "ADD";
export const isMoveCommand = (command: Command): command is MoveCommand =>
  command.type === "MOVE";
export const isDeleteCommand = (command: Command): command is DeleteCommand =>
  command.type === "DELETE";
export const isConnectCommand = (command: Command): command is ConnectCommand =>
  command.type === "CONNECT";
export const isDisconnectCommand = (
  command: Command,
): command is DisconnectCommand => command.type === "DISCONNECT";
export const isMergeStreamsCommand = (
  command: Command,
): command is MergeStreamsCommand => command.type === "MERGE_STREAMS";