js/graph.mjs

/**
 * Validate a potential connection.
 */
export function isValidConnection(connection, nodes, conns, validator) {
    if (!connection.from || !connection.to) return false

    // Self-connection not allowed by default
    if (connection.from === connection.to) return false

    // 節點種類語義: input(僅出點)不可作為連線終點, output(僅入點)不可作為連線起點
    const fromNode = nodes.find(n => n.id === connection.from)
    const toNode = nodes.find(n => n.id === connection.to)
    if (fromNode && fromNode.type === 'output') return false
    if (toNode && toNode.type === 'input') return false

    // Check duplicate (same from→to path)
    const duplicate = conns.find(
        e => e.from === connection.from && e.to === connection.to
    )
    if (duplicate) return false

    // Custom validator
    if (validator && !validator(connection)) return false

    return true
}

let _idCounter = 0

/**
 * Generate a unique ID.
 */
export function generateId() {
    _idCounter++
    return `${Date.now()}-${_idCounter}-${Math.random().toString(36).slice(2, 7)}`
}