All files / web/src/components/toys/euclid/engine selectors.ts

92.3% Statements 36/39
94.11% Branches 16/17
100% Functions 1/1
92.3% Lines 36/39

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 401x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 28x 24x 28x 12x 12x 65x 12x 12x 12x 12x 12x 12x 12x 58x 12x 3x 12x 12x 12x        
import type {
  ConstructionState,
  ConstructionCircle,
  ConstructionSegment,
  ElementSelector,
} from '../types'
 
/**
 * Resolve an ElementSelector to its runtime element ID.
 *
 * - String selectors (point IDs like "pt-A") pass through directly.
 * - Circle selectors match by (centerId, radiusPointId).
 * - Segment selectors match by (fromId, toId), order-insensitive.
 *
 * Returns null if no matching element exists in state.
 */
export function resolveSelector(sel: ElementSelector, state: ConstructionState): string | null {
  if (typeof sel === 'string') return sel
 
  if (sel.kind === 'circle') {
    const match = state.elements.find(
      (e): e is ConstructionCircle =>
        e.kind === 'circle' && e.centerId === sel.centerId && e.radiusPointId === sel.radiusPointId
    )
    return match?.id ?? null
  }
 
  if (sel.kind === 'segment') {
    const match = state.elements.find(
      (e): e is ConstructionSegment =>
        e.kind === 'segment' &&
        ((e.fromId === sel.fromId && e.toId === sel.toId) ||
          (e.fromId === sel.toId && e.toId === sel.fromId))
    )
    return match?.id ?? null
  }

  return null
}