import type { SerializedProjectCommand } from "./project-command.model.js"; export const circuitSectionRenumberCommandType = "circuit.renumber-section" as const; export const circuitSectionRenumberCommandSchemaVersion = 1 as const; export interface CircuitSectionRenumberAssignment { circuitId: string; expectedEquipmentIdentifier: string; targetEquipmentIdentifier: string; } export interface CircuitSectionRenumberCommandPayload { sectionId: string; assignments: CircuitSectionRenumberAssignment[]; } export interface CircuitSectionRenumberProjectCommand extends SerializedProjectCommand { schemaVersion: typeof circuitSectionRenumberCommandSchemaVersion; type: typeof circuitSectionRenumberCommandType; } export function createCircuitSectionRenumberProjectCommand( sectionId: string, assignments: CircuitSectionRenumberAssignment[] ): CircuitSectionRenumberProjectCommand { const command: CircuitSectionRenumberProjectCommand = { schemaVersion: circuitSectionRenumberCommandSchemaVersion, type: circuitSectionRenumberCommandType, payload: { sectionId, assignments }, }; assertCircuitSectionRenumberProjectCommand(command); return command; } export function assertCircuitSectionRenumberProjectCommand( command: SerializedProjectCommand ): asserts command is CircuitSectionRenumberProjectCommand { if ( command.schemaVersion !== circuitSectionRenumberCommandSchemaVersion || command.type !== circuitSectionRenumberCommandType ) { throw new Error("Unsupported circuit section renumber command."); } if (!isPlainObject(command.payload)) { throw new Error( "Circuit section renumber payload must be an object." ); } const { sectionId, assignments } = command.payload; assertNonEmptyString(sectionId, "sectionId"); if (!Array.isArray(assignments) || assignments.length === 0) { throw new Error( "Circuit section renumber command requires assignments." ); } const circuitIds = new Set(); const expectedIdentifiers = new Set(); const targetIdentifiers = new Set(); let hasChangedIdentifier = false; for (const assignment of assignments) { if (!isPlainObject(assignment)) { throw new Error( "Circuit section renumber command contains an invalid assignment." ); } assertNonEmptyString(assignment.circuitId, "circuitId"); assertNonEmptyString( assignment.expectedEquipmentIdentifier, "expectedEquipmentIdentifier" ); assertNonEmptyString( assignment.targetEquipmentIdentifier, "targetEquipmentIdentifier" ); if (circuitIds.has(assignment.circuitId)) { throw new Error( "Circuit section renumber command contains duplicate circuit ids." ); } if ( expectedIdentifiers.has( assignment.expectedEquipmentIdentifier ) ) { throw new Error( "Circuit section renumber command contains duplicate expected identifiers." ); } if ( targetIdentifiers.has(assignment.targetEquipmentIdentifier) ) { throw new Error( "Circuit section renumber command contains duplicate target identifiers." ); } if ( assignment.expectedEquipmentIdentifier !== assignment.targetEquipmentIdentifier ) { hasChangedIdentifier = true; } circuitIds.add(assignment.circuitId); expectedIdentifiers.add( assignment.expectedEquipmentIdentifier ); targetIdentifiers.add(assignment.targetEquipmentIdentifier); } if (!hasChangedIdentifier) { throw new Error( "Circuit section renumber command must change at least one identifier." ); } } function assertNonEmptyString( value: unknown, field: string ): asserts value is string { if (typeof value !== "string" || !value.trim()) { throw new Error(`${field} must be a non-empty string.`); } } function isPlainObject(value: unknown): value is Record { return value !== null && typeof value === "object" && !Array.isArray(value); }