Public/Edge.ps1

function Edge 
{
    <#
        .Description
        This defines an edge between two or more nodes

        .Example
        Graph g {
            Edge FirstNode SecondNode
        }

        Generates this graph syntax:

        digraph g {
            "FirstNode"->"SecondNode"
        }
        
        .Example
        $folder = Get-ChildItem -Recurse -Directory
        graph g {
            $folder | %{ edge $_.parent $_.name }
        }

        # with parameter names specified
        graph g {
            $folder | %{ edge -From $_.parent -To $_.name }
        }

        # with scripted properties
        graph g {
            edge $folder -FromScript {$_.parent} -ToScript {$_.name}
        }

        .Example
        $folder = Get-ChildItem -Recurse -Directory
        

        .Example
        graph g {
            edge (1..3) (5..7)
            edge top bottom @{label="line label"}
            edge (10..13)
            edge one,two,three,four
        }

        .Notes
        If an array is specified for the From property, but not for the To property, then the From list will be procesed in order and will map the array in a chain.

    #>

    [cmdletbinding(DefaultParameterSetName='Node')]
    param(
        # start node or source of edge
        [Parameter(
            Mandatory = $true, 
            Position = 0,
            ParameterSetName='Node'
        )]
        [alias('NodeName','Name','SourceName','LeftHandSide','lhs')]
        [string[]]
        $From,

        # Destination node or target of edge
        [Parameter(
            Mandatory = $false, 
            Position = 1,
            ParameterSetName='Node'
        )]
        [alias('Destination','TargetName','RightHandSide','rhs')]
        [string[]]
        $To,

        # Hashtable that gets translated to an edge modifier
        [Parameter(
            Position = 2,
            ParameterSetName='Node'
        )]
        [Parameter(
            Position = 1,
            ParameterSetName='script'
        )]        
        [hashtable]
        $Attributes,

        # a list of nodes to process
        [Parameter(
            Mandatory = $true, 
            Position = 0,
            ValueFromPipeline = $true,
            ParameterSetName='script'
        )]
        [Alias('InputObject')]
        [Object[]]
        $Node,

        # start node script or source of edge
        [Parameter(
            ParameterSetName='script')]
        [alias('FromScriptBlock','SourceScript')]
        [scriptblock]
        $FromScript = {$_},

        # Destination node script or target of edge
        [Parameter(ParameterSetName='script')]
        [alias('ToScriptBlock','TargetScript')]
        [scriptblock]
        $ToScript = {$null},

        # A string for using native attribute syntax
        [string]
        $LiteralAttribute = $null,

        # Not used, but can be specified for verbosity
        [switch]
        $Default
    )

    begin
    {
        if( -Not [string]::IsNullOrEmpty($LiteralAttribute))
        {
            $GraphVizAttribute = $LiteralAttribute
        }
    }

    process 
    {
        if($Node.count -eq 1 -and $node[0] -is [Hashtable] -and !$PSBoundParameters.ContainsKey('FromScript') -and !$PSBoundParameters.ContainsKey('ToScript'))
        { #Deducing the pattern 'edge @{}' as default edge definition
            node 'edge' -attributes $Node[0]
        }
        elseif($null -ne $Node )
        { # Used when scripted properties are specified
            foreach($item in $Node)
            {            
                $fromValue = (@($item).ForEach($FromScript))
                $toValue = (@($item).ForEach($ToScript))
                $LiteralAttribute = ConvertTo-GraphVizAttribute -Attributes $Attributes -InputObject $item

                edge -From $fromValue -To $toValue -LiteralAttribute $LiteralAttribute
            }
        } 
        else
        {
            if ($null -ne $Attributes -and [string]::IsNullOrEmpty($LiteralAttribute))
            {
                $GraphVizAttribute = ConvertTo-GraphVizAttribute -Attributes $Attributes
            }        
        
            if ($null -ne $To)
            { # If we have a target array, cross multiply results
                foreach($sNode in $From)
                {                    
                    foreach($tNode in $To)
                    {                        
                      
                        Write-Output ('{0}{1}->{2} {3}' -f  (Get-Indent),                        
                            (Format-Value $sNode -Edge),
                            (Format-Value $tNode -Edge),                            
                            $GraphVizAttribute
                        )
                    }
                }
            }
            else
            { # If we have a single array, connect them sequentially.
                for($index=0; $index -lt ($From.Count - 1); $index++)
                {
                    Write-Output ('{0}{1}->{2} {3}' -f (Get-Indent),
                        (Format-Value $From[$index] -Edge),
                        (Format-Value $From[$index + 1] -Edge),
                        $GraphVizAttribute
                    )
                }
            }
        }
    }
}