# Functions

Import these from `@grafloria/engine`.

## Functions

### `remapNodePortIds`

Re-assign fresh ids to every port on a freshly-cloned node.

Why this is needed: {@link NodeModel.fromJSON} restores each port with its
ORIGINAL serialized id, so a clone would otherwise share port ids with its
source node. Links reference the engine's nanoid port ids directly (they are
NOT `"nodeId:portName"` strings), and node lookup resolves a node by "which
node owns this port id" — duplicate port ids across nodes make that lookup
ambiguous and break pasted/duplicated links.

For each port this:
 - generates a new port id and records `oldPortId -> newPortId` in `portIdMap`
   so the caller can remap link endpoints,
 - points the port back at its new owning node,
 - rebuilds the node's ports Map (whose KEYS are the port ids) so lookups by
   id keep working.

```ts
function remapNodePortIds(
  node: NodeModel,
  newNodeId: string,
  portIdMap: Map<string, string>,
): void
```

**Parameters**

- `node`: the cloned node (mutated in place)
- `newNodeId`: the clone's node id (ports' `nodeId` is set to this)
- `portIdMap`: accumulates oldPortId -> newPortId across all cloned nodes

### `resolveLinkNodeIds`

Resolve the ids of the nodes a link is attached to.

WHY THIS EXISTS: a link's `sourcePortId`/`targetPortId` are PORT ids — engine
nanoids — NOT `"nodeId:portName"` strings. Commands that used
`portId.split(':')[0]` to get a node id therefore resolved nothing for links
created the production way (`diagram.connectNodes()` / the interactive connect
path), which silently:
  - made CopyCommand skip every link between the copied nodes, and
  - made DeleteSelectionCommand leave ORPHAN links behind when it deleted the
    nodes at both ends (`removeNode()` does not cascade to links).

Resolution order:
  1. the ids LinkModel caches (`sourceNodeId` / `targetNodeId`, backfilled by
     `addLink()` / `restoreLink()` from the port index),
  2. the diagram's O(1) port index (`getNodeByPortId`),
  3. the legacy `"nodeId:portName"` convention — still used by hand-built test
     links and older documents — but only when it names a node that actually
     exists.

```ts
function resolveLinkNodeIds(
  diagram: any,
  link: { sourcePortId: string; targetPortId: string; sourceNodeId?: string; targetNodeId?: string }
): { sourceNodeId?: string; targetNodeId?: string }
```

**Returns** the owning node ids; either may be `undefined` for a dangling endpoint.
