Format-Splat.psm1

Write-Verbose 'Importing from [C:\MyProjects\Format-Splat\Format-Splat\private]'
Write-Verbose 'Importing from [C:\MyProjects\Format-Splat\Format-Splat\public]'
# .\Format-Splat\public\Format-Splat.ps1
function Format-Splat
{
    <#
    .DESCRIPTION
    formats a function call into a splatted call

    .EXAMPLE
    $text = 'Copy-Item -Path $path -Destination c:\temp -Force'

    PS> Format-Splat $text

    $item = @{
        Path = $path
        Destination = 'c:\temp'
        Force = $true
    }
    Copy-Item @item


    #>

    [OutPutType('System.String')]
    [Cmdletbinding()]
    param
    (
        # The text to format into an appropriate splat command
        [parameter(
            Mandatory,
            Position = 0,
            ValueFromPipeline
        )]
        [string]
        $InputObject
    )

    $script = [scriptblock]::Create($InputObject)
    $ast = $script.ast

    $command = $ast | Select-AST -Type CommandAst

    $parameters = [ordered]@{}
    $currentParameter = $null
    $function = ''
    $parent = $null
    $other = @()

    $mode = 'function'
    foreach ($token in $command.CommandElements)
    {
        if ($null -ne $parent -and $parent -ne $token.Parent)
        {
            continue
        }

        switch ($mode)
        {
            'function'
            {
                if ($token -is [System.Management.Automation.Language.StringConstantExpressionAst])
                {
                    $function = $token.Value
                    $mode = 'parameter'
                    $parent = $token.Parent
                }
            }
            'value'
            {
                if ($token -is [System.Management.Automation.Language.StringConstantExpressionAst])
                {
                    $parameters[$currentParameter] = "'{0}'" -f $token.Value
                }
                elseif (-not($token -is [System.Management.Automation.Language.CommandParameterAst]))
                {
                    $parameters[$currentParameter] = $token.Extent
                }
                $currentParameter = $null
                $mode = 'parameter'
            }
            'parameter'
            {
                if ($token -is [System.Management.Automation.Language.CommandParameterAst])
                {
                    $currentParameter = $token.ParameterName
                    $parameters[$currentParameter] = '$true'
                    $mode = 'value'
                }
                else
                {
                    $other += $token.Extent
                }
            }
        }
    }

    if ($parameters.count -lt 1)
    {
        return $InputObject
    }

    $output = @()
    $splatName = $function -split '-' | Select-Object -Last 1
    $splatName = $splatName.substring(0, 1).tolower() + $splatName.substring(1)

    $output += '${0} = @{{' -f $splatName
    foreach ($node in $parameters.GetEnumerator())
    {
        $paramName = $node.Name.substring(0, 1).toUpper() + $node.Name.substring(1)
        $output += ' {0} = {1}' -f $paramName, $Node.Value
    }
    $output += '}'
    if ($other.count -gt 0)
    {
        $output += '{0} {1} @{2}' -f $function, ($other -join ' '), $splatName
    }
    else
    {
        $output += '{0} @{1}' -f $function, $splatName
    }

    $output | Out-String -Width 1000
}

# .\Format-Splat\public\Format-VSCodeSplat.ps1
function Format-VSCodeSplat
{
    <#
    .DESCRIPTION
    Takes the selected function with parameters and creates the needed splat call

    .EXAMPLE
    Copy-Item -Path $path -Destination c:\temp -Force

    $item = @{
        Path = $path
        Destination = 'c:\temp'
        Force = $true
    }
    Copy-Item @item

    #>

    [Cmdletbinding()]
    param
    (
        # VSCode context
        [Microsoft.PowerShell.EditorServices.Extensions.EditorContext]
        $context
    )

    try 
    {
        if ($null -ne $context)
        {
            $text = $context.CurrentFile.GetText($context.SelectedRange) | Out-String
            $output = Format-Splat -InputObject $text
            if ($output)
            {
                $context.CurrentFile.InsertText($output, $context.SelectedRange)
            }
        }
    }
    catch 
    {
        $pseditor.window.ShowWarningMessage($PSitem.ToString())
    }
}

if ($psEditor)
{
    $EditorCommand = @{
        Name           = 'Invoke-VSSplat'
        DisplayName    = 'Refactor: splat parameters for cmdlet'
        Function       = 'Format-VSCodeSplat'
        SuppressOutput = $true
    }
    Register-EditorCommand  @EditorCommand
}









Write-Verbose 'Importing from [C:\MyProjects\Format-Splat\Format-Splat\classes]'