Some checks failed
Deploy analytics worker / Deploy analytics worker to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
i18n upload strings / Upload latest strings (push) Failing after 1s
Deploy bemo / Deploy bemo to ${{ (github.ref == 'refs/heads/bemo-production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
Deploy grafana resources / ${{ github.event_name == 'push' && 'Deploy grafana resources' || 'Validate grafana resources (dry run)' }} (push) Failing after 0s
End to end tests (dotcom) / Check for relevant changes (push) Failing after 0s
End to end tests (examples) / Check for relevant changes (push) Failing after 0s
End to end tests (mermaid readability) / Check for relevant changes (push) Failing after 1s
End to end tests (perf) / Check for relevant changes (push) Failing after 0s
Publish editor extensions / Publish editor extensions (push) Failing after 1s
Publish SDK packages / Remove the publish-packages label (push) Has been skipped
Checks / Tests & checks (push) Has been cancelled
Checks / Build all projects (push) Has been cancelled
Deploy templates / Deploy templates (push) Has been cancelled
End to end tests (dotcom) / End to end tests (dotcom) (push) Has been cancelled
End to end tests (mermaid readability) / End to end tests (mermaid readability) (push) Has been cancelled
End to end tests (perf) / End to end tests (perf) (push) Has been cancelled
Deploy .com / Deploy dotcom to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Has been cancelled
End to end tests (examples) / End to end tests (examples) (push) Has been cancelled
Publish SDK packages / Publish SDK packages (push) Has been cancelled
Publish SDK packages / Tell user released version (push) Has been cancelled
Publish SDK packages / Publishes code templates to separate repositories (push) Has been cancelled
Publish SDK packages / Deploys the template demos with the new SDK version (push) Has been cancelled
97 lines
2.9 KiB
TypeScript
97 lines
2.9 KiB
TypeScript
/**
|
|
* This file contains functions for working with ports and connections on nodes.
|
|
*/
|
|
import { createComputedCache, Editor, TLShapeId } from 'tldraw'
|
|
import { getConnectionBindings } from '../connection/ConnectionBindingUtil'
|
|
import { PortId } from '../ports/Port'
|
|
import { NodeShape } from './NodeShapeUtil'
|
|
import { getNodeTypePorts, NodeTypePorts } from './nodeTypes'
|
|
|
|
/**
|
|
* Get the ports for a node. This is cached, because we only want to re-evaluate it when the
|
|
* underlying records change.
|
|
*/
|
|
export function getNodePorts(editor: Editor, shape: NodeShape | TLShapeId): NodeTypePorts {
|
|
return nodePortsCache.get(editor, typeof shape === 'string' ? shape : shape.id) ?? {}
|
|
}
|
|
const nodePortsCache = createComputedCache(
|
|
'ports',
|
|
(editor: Editor, node: NodeShape): NodeTypePorts => getNodeTypePorts(editor, node)
|
|
)
|
|
|
|
/**
|
|
* A connection from one node to another.
|
|
*/
|
|
export interface NodePortConnection {
|
|
connectedShapeId: TLShapeId
|
|
connectionId: TLShapeId
|
|
terminal: 'start' | 'end'
|
|
ownPortId: PortId
|
|
connectedPortId: PortId
|
|
}
|
|
|
|
/**
|
|
* Get the connections for a node. This is cached.
|
|
*/
|
|
export function getNodePortConnections(
|
|
editor: Editor,
|
|
shape: NodeShape | TLShapeId
|
|
): NodePortConnection[] {
|
|
return nodePortConnectionsCache.get(editor, typeof shape === 'string' ? shape : shape.id) ?? []
|
|
}
|
|
const nodePortConnectionsCache = createComputedCache(
|
|
'port connections',
|
|
(editor: Editor, node: NodeShape) => {
|
|
const bindings = editor.getBindingsToShape(node.id, 'connection')
|
|
|
|
const connections: NodePortConnection[] = []
|
|
for (const binding of bindings) {
|
|
const oppositeTerminal = binding.props.terminal === 'start' ? 'end' : 'start'
|
|
const oppositeBinding = getConnectionBindings(editor, binding.fromId)[oppositeTerminal]
|
|
if (!oppositeBinding) continue
|
|
|
|
connections.push({
|
|
connectedShapeId: oppositeBinding.toId,
|
|
connectionId: binding.fromId,
|
|
terminal: binding.props.terminal,
|
|
ownPortId: binding.props.portId,
|
|
connectedPortId: oppositeBinding.props.portId,
|
|
})
|
|
}
|
|
|
|
return connections
|
|
},
|
|
{
|
|
areRecordsEqual: (a, b) => a.id === b.id,
|
|
}
|
|
)
|
|
|
|
/**
|
|
* Traverse the graph from a starting node, in a given direction, returning all the nodes that are
|
|
* connected to it (including the starting node).
|
|
*/
|
|
export function getAllConnectedNodes(
|
|
editor: Editor,
|
|
startingNode: TLShapeId | NodeShape,
|
|
direction?: 'start' | 'end'
|
|
) {
|
|
const toVisit = [typeof startingNode === 'string' ? startingNode : startingNode.id]
|
|
const found = new Set<TLShapeId>()
|
|
|
|
while (toVisit.length > 0) {
|
|
const nodeId = toVisit.shift()!
|
|
const node = editor.getShape(nodeId)
|
|
if (!node || !editor.isShapeOfType(node, 'node')) continue
|
|
|
|
if (found.has(node.id)) continue
|
|
found.add(node.id)
|
|
|
|
for (const connection of getNodePortConnections(editor, node)) {
|
|
if (direction && connection.terminal !== direction) continue
|
|
toVisit.push(connection.connectedShapeId)
|
|
}
|
|
}
|
|
|
|
return found
|
|
}
|