PesterConverter.psm1

#Region '.\prefix.ps1' -1

$script:dscResourceCommonModulePath = Join-Path -Path $PSScriptRoot -ChildPath 'Modules/DscResource.Common'
Import-Module -Name $script:dscResourceCommonModulePath

$script:localizedData = Get-LocalizedData -DefaultUICulture 'en-US'
#EndRegion '.\prefix.ps1' 5
#Region '.\Private\Convert-ShouldBe.ps1' -1

<#
    .SYNOPSIS
        Converts a command `Should -Be` to the specified Pester syntax.
 
    .DESCRIPTION
        The Convert-ShouldBe function is used to convert a command `Should -Be` to
        the specified Pester syntax.
 
    .PARAMETER CommandAst
        The CommandAst object representing the command to be converted.
 
    .PARAMETER Pester6
        Specifies that the command should be converted to Pester version 6 syntax.
 
    .PARAMETER UseNamedParameters
        Specifies whether to use named parameters in the converted syntax.
 
    .PARAMETER UsePositionalParameters
        Specifies whether to use positional parameters in the converted syntax,
        where supported.
 
    .EXAMPLE
        $commandAst = [System.Management.Automation.Language.Parser]::ParseInput('Should -Be "Test"')
        Convert-ShouldBe -CommandAst $commandAst -Pester6
 
        This example converts the `Should -Be "Test"` command to Pester 6 syntax.
 
    .NOTES
        Pester 5 Syntax:
            Should -Be [[-ActualValue] <Object>] [-Not] [[-ExpectedValue] <Object>] [-Because <Object>]
 
            Positional parameters:
                Position 1: ExpectedValue
                Position 2: Because
                Position 3: ActualValue
 
        Pester 6 Syntax:
            Should-Be [[-Actual] <Object>] [-Expected] <Object> [-Because <String>]
            Should-NotBe [[-Actual] <Object>] [-Expected] <Object> [-Because <String>]
 
            Positional parameters:
                Position 1: Expected
                Position 2: Actual
#>

function Convert-ShouldBe
{
    [CmdletBinding()]
    [OutputType([System.String])]
    param
    (
        [Parameter(Mandatory = $true)]
        [System.Management.Automation.Language.CommandAst]
        $CommandAst,

        [Parameter(Mandatory = $true, ParameterSetName = 'Pester6')]
        [System.Management.Automation.SwitchParameter]
        $Pester6,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $UseNamedParameters,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $UsePositionalParameters
    )

    $assertBoundParameterParameters = @{
        BoundParameterList     = $PSBoundParameters
        MutuallyExclusiveList1 = @('UseNamedParameters')
        MutuallyExclusiveList2 = @('UsePositionalParameters')
    }

    Assert-BoundParameter @assertBoundParameterParameters

    Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ParsingCommandAst -f $CommandAst.Extent.Text)

    # Determine if the command is negated
    $isNegated = Test-PesterCommandNegated -CommandAst $CommandAst

    $sourceSyntaxVersion = Get-PesterCommandSyntaxVersion -CommandAst $CommandAst

    # Parse the command elements and convert them to Pester 6 syntax
    if ($PSCmdlet.ParameterSetName -eq 'Pester6')
    {
        Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ConvertingFromTo -f $sourceSyntaxVersion, '6')

        # Add the correct Pester command based on negation
        $newExtentText = $isNegated ? 'Should-NotBe' : 'Should-Be'

        $getPesterCommandParameterParameters = @{
            CommandAst          = $CommandAst
            CommandName         = 'Should'
            IgnoreParameter     = @(
                'Be'
                'EQ'
                'Not'
            )
            PositionalParameter = @(
                'ExpectedValue'
                'Because'
                'ActualValue'
            )
        }

        $commandParameters = Get-PesterCommandParameter @getPesterCommandParameterParameters

        # Parameter 'Because' is only supported as named parameter in Pester 6 syntax.
        if ($commandParameters.Because)
        {
            $commandParameters.Because.Positional = $false
        }

        # Determine if named or positional parameters should be forcibly used
        if ($UseNamedParameters.IsPresent)
        {
            $commandParameters.Keys.ForEach({ $commandParameters.$_.Positional = $false })
        }
        elseif ($UsePositionalParameters.IsPresent)
        {
            # First set all to named parameters
            $commandParameters.Keys.ForEach({ $commandParameters.$_.Positional = $false })

            <#
                If a previous positional parameter is missing then the ones behind
                it cannot be set to positional.
            #>

            if ($commandParameters.ExpectedValue)
            {
                $commandParameters.ExpectedValue.Positional = $true

                if ($commandParameters.ActualValue)
                {
                    $commandParameters.ActualValue.Positional = $true
                }
            }
        }

        $newExtentText += $commandParameters.ExpectedValue.Positional ? (' {0}' -f $commandParameters.ExpectedValue.ExtentText) : ''
        $newExtentText += $commandParameters.ActualValue.Positional ? (' {0}' -f $commandParameters.ActualValue.ExtentText) : ''

        # Holds the new parameter names so they can be added in alphabetical order.
        $parameterNames = @()

        foreach ($currentParameter in $commandParameters.Keys)
        {
            if ($commandParameters.$currentParameter.Positional -eq $true)
            {
                continue
            }

            switch ($currentParameter)
            {
                'ActualValue'
                {
                    $parameterNames += @{
                        Actual = 'ActualValue'
                    }

                    break
                }

                'ExpectedValue'
                {
                    $parameterNames += @{
                        Expected = 'ExpectedValue'
                    }

                    break
                }

                default
                {
                    $parameterNames += @{
                        $currentParameter = $currentParameter
                    }

                    break
                }
            }
        }

        # This handles the named parameters in the command elements, added in alphabetical order.
        foreach ($currentParameter in $parameterNames.Keys | Sort-Object)
        {
            $originalParameterName = $parameterNames.$currentParameter

            $newExtentText += ' -{0} {1}' -f $currentParameter, $commandParameters.$originalParameterName.ExtentText
        }
    }

    Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ConvertedCommand -f $CommandAst.Extent.Text, $newExtentText)

    return $newExtentText
}
#EndRegion '.\Private\Convert-ShouldBe.ps1' 196
#Region '.\Private\Convert-ShouldBeExactly.ps1' -1

<#
    .SYNOPSIS
        Converts a command `Should -BeExactly` to the specified Pester syntax.
 
    .DESCRIPTION
        The Convert-ShouldBe function is used to convert a command `Should -BeExactly` to
        the specified Pester syntax.
 
    .PARAMETER CommandAst
        The CommandAst object representing the command to be converted.
 
    .PARAMETER Pester6
        Specifies that the command should be converted to Pester version 6 syntax.
 
    .PARAMETER UseNamedParameters
        Specifies whether to use named parameters in the converted syntax.
 
    .PARAMETER UsePositionalParameters
        Specifies whether to use positional parameters in the converted syntax,
        where supported.
 
    .EXAMPLE
        $commandAst = [System.Management.Automation.Language.Parser]::ParseInput('Should -BeExactly "Test"')
        Convert-ShouldBeExactly -CommandAst $commandAst -Pester6
 
        This example converts the `Should -BeExactly "Test"` command to Pester 6 syntax.
 
    .NOTES
        Pester 5 Syntax:
            Should -BeExactly [[-ActualValue] <Object>] [-Not] [[-ExpectedValue] <Object>] [-Because <Object>]
 
            Positional parameters:
                Position 1: ExpectedValue
                Position 2: Because
                Position 3: ActualValue
 
        Pester 6 Syntax:
            Should-BeString [[-Actual] <Object>] [[-Expected] <String>] [-Because <String>] [-CaseSensitive] [-IgnoreWhitespace]
            Should-NotBeString [[-Actual] <Object>] [[-Expected] <String>] [-Because <String>] [-CaseSensitive] [-IgnoreWhitespace]
 
            Positional parameters:
                Position 1: Expected
                Position 2: Actual
#>

function Convert-ShouldBeExactly
{
    [CmdletBinding()]
    [OutputType([System.String])]
    param
    (
        [Parameter(Mandatory = $true)]
        [System.Management.Automation.Language.CommandAst]
        $CommandAst,

        [Parameter(Mandatory = $true, ParameterSetName = 'Pester6')]
        [System.Management.Automation.SwitchParameter]
        $Pester6,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $UseNamedParameters,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $UsePositionalParameters
    )

    $assertBoundParameterParameters = @{
        BoundParameterList     = $PSBoundParameters
        MutuallyExclusiveList1 = @('UseNamedParameters')
        MutuallyExclusiveList2 = @('UsePositionalParameters')
    }

    Assert-BoundParameter @assertBoundParameterParameters

    Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ParsingCommandAst -f $CommandAst.Extent.Text)

    # Determine if the command is negated
    $isNegated = Test-PesterCommandNegated -CommandAst $CommandAst

    $sourceSyntaxVersion = Get-PesterCommandSyntaxVersion -CommandAst $CommandAst

    # Parse the command elements and convert them to Pester 6 syntax
    if ($PSCmdlet.ParameterSetName -eq 'Pester6')
    {
        Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ConvertingFromTo -f $sourceSyntaxVersion, '6')

        # Add the correct Pester command based on negation
        $newExtentText = $isNegated ? 'Should-NotBeString' : 'Should-BeString'

        # Always add the `-CaseSensitive` parameter since BeExactly was case-sensitive.
        $newExtentText += ' -CaseSensitive'

        $getPesterCommandParameterParameters = @{
            CommandAst          = $CommandAst
            CommandName         = 'Should'
            IgnoreParameter     = @(
                'CEQ'
                'BeExactly'
                'Not'
            )
            PositionalParameter = @(
                'ExpectedValue'
                'Because'
                'ActualValue'
            )
        }

        $commandParameters = Get-PesterCommandParameter @getPesterCommandParameterParameters

        # Parameter 'Because' is only supported as named parameter in Pester 6 syntax.
        if ($commandParameters.Because)
        {
            $commandParameters.Because.Positional = $false
        }

        # Determine if named or positional parameters should be forcibly used
        if ($UseNamedParameters.IsPresent)
        {
            $commandParameters.Keys.ForEach({ $commandParameters.$_.Positional = $false })
        }
        elseif ($UsePositionalParameters.IsPresent)
        {
            # First set all to named parameters
            $commandParameters.Keys.ForEach({ $commandParameters.$_.Positional = $false })

            <#
                If a previous positional parameter is missing then the ones behind
                it cannot be set to positional.
            #>

            if ($commandParameters.ExpectedValue)
            {
                $commandParameters.ExpectedValue.Positional = $true

                if ($commandParameters.ActualValue)
                {
                    $commandParameters.ActualValue.Positional = $true
                }
            }
        }

        $newExtentText += $commandParameters.ExpectedValue.Positional ? (' {0}' -f $commandParameters.ExpectedValue.ExtentText) : ''
        $newExtentText += $commandParameters.ActualValue.Positional ? (' {0}' -f $commandParameters.ActualValue.ExtentText) : ''

        # Holds the new parameter names so they can be added in alphabetical order.
        $parameterNames = @()

        foreach ($currentParameter in $commandParameters.Keys)
        {
            if ($commandParameters.$currentParameter.Positional -eq $true)
            {
                continue
            }

            switch ($currentParameter)
            {
                'ActualValue'
                {
                    $parameterNames += @{
                        Actual = 'ActualValue'
                    }

                    break
                }

                'ExpectedValue'
                {
                    $parameterNames += @{
                        Expected = 'ExpectedValue'
                    }

                    break
                }

                default
                {
                    $parameterNames += @{
                        $currentParameter = $currentParameter
                    }

                    break
                }
            }
        }

        # This handles the named parameters in the command elements, added in alphabetical order.
        foreach ($currentParameter in $parameterNames.Keys | Sort-Object)
        {
            $originalParameterName = $parameterNames.$currentParameter

            $newExtentText += ' -{0} {1}' -f $currentParameter, $commandParameters.$originalParameterName.ExtentText
        }
    }

    Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ConvertedCommand -f $CommandAst.Extent.Text, $newExtentText)

    return $newExtentText
}
#EndRegion '.\Private\Convert-ShouldBeExactly.ps1' 199
#Region '.\Private\Convert-ShouldBeFalse.ps1' -1

<#
    .SYNOPSIS
        Converts a command `Should -BeFalse` to the specified Pester syntax.
 
    .DESCRIPTION
        The Convert-ShouldBeFalse function is used to convert a command `Should -BeFalse` to
        the specified Pester syntax.
 
    .PARAMETER CommandAst
        The CommandAst object representing the command to be converted.
 
    .PARAMETER Pester6
        Specifies that the command should be converted to Pester version 6 syntax.
 
    .PARAMETER UseNamedParameters
        Specifies whether to use named parameters in the converted syntax.
 
    .PARAMETER UsePositionalParameters
        Specifies whether to use positional parameters in the converted syntax,
        where supported.
 
    .EXAMPLE
        $commandAst = [System.Management.Automation.Language.Parser]::ParseInput('Should -BeFalse')
        Convert-ShouldBeFalse -CommandAst $commandAst -Pester6
 
        This example converts the `Should -BeFalse` command to Pester 6 syntax.
 
    .NOTES
        Pester 5 Syntax:
            Should -BeFalse [[-ActualValue] <Object>] [[-Because] <Object>] [-Not]
 
            Positional parameters:
                Position 1: Because
                Position 2: ActualValue
 
        Pester 6 Syntax:
            Should-BeFalse [[-Actual] <Object>] [[-Because] <String>]
 
            Positional parameters:
                Position 1: Actual
                Position 2: Because
 
        Conversion notes:
            If the Pester 5 syntax is negated it must be converted to Should-BeTrue.
#>

function Convert-ShouldBeFalse
{
    [CmdletBinding()]
    [OutputType([System.String])]
    param
    (
        [Parameter(Mandatory = $true)]
        [System.Management.Automation.Language.CommandAst]
        $CommandAst,

        [Parameter(Mandatory = $true, ParameterSetName = 'Pester6')]
        [System.Management.Automation.SwitchParameter]
        $Pester6,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $UseNamedParameters,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $UsePositionalParameters
    )

    $assertBoundParameterParameters = @{
        BoundParameterList     = $PSBoundParameters
        MutuallyExclusiveList1 = @('UseNamedParameters')
        MutuallyExclusiveList2 = @('UsePositionalParameters')
    }

    Assert-BoundParameter @assertBoundParameterParameters

    Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ParsingCommandAst -f $CommandAst.Extent.Text)

    # Determine if the command is negated
    $isNegated = Test-PesterCommandNegated -CommandAst $CommandAst

    $sourceSyntaxVersion = Get-PesterCommandSyntaxVersion -CommandAst $CommandAst

    # Parse the command elements and convert them to Pester 6 syntax
    if ($PSCmdlet.ParameterSetName -eq 'Pester6')
    {
        Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ConvertingFromTo -f $sourceSyntaxVersion, '6')

        # Add the correct Pester command based on negation
        $newExtentText = $isNegated ? 'Should-BeTrue' : 'Should-BeFalse'

        $getPesterCommandParameterParameters = @{
            CommandAst          = $CommandAst
            CommandName         = 'Should'
            IgnoreParameter     = 'BeFalse', 'Not'
            PositionalParameter = 'Because', 'ActualValue'
        }

        $commandParameters = Get-PesterCommandParameter @getPesterCommandParameterParameters

        # Determine if named or positional parameters should be forcibly used
        if ($UseNamedParameters.IsPresent)
        {
            $commandParameters.Keys.ForEach({ $commandParameters.$_.Positional = $false })
        }
        elseif ($UsePositionalParameters.IsPresent)
        {
            # First set all to named parameters
            $commandParameters.Keys.ForEach({ $commandParameters.$_.Positional = $false })

            <#
                If a previous positional parameter is missing then the ones behind
                it cannot be set to positional.
            #>

            if ($commandParameters.Because)
            {
                $commandParameters.Because.Positional = $true

                if ($commandParameters.ActualValue)
                {
                    $commandParameters.ActualValue.Positional = $true
                }
            }
        }

        $newExtentText += $commandParameters.ActualValue.Positional ? (' {0}' -f $commandParameters.ActualValue.ExtentText) : ''

        if ($commandParameters.Because -and $commandParameters.Because.Positional)
        {
            # Only add second positional if the first positional was present.
            if ($commandParameters.ActualValue.Positional)
            {
                $newExtentText += ' {0}' -f $commandParameters.Because.ExtentText
            }
            else
            {
                # First positional parameter was not present, so set the second to named parameter.
                $commandParameters.Because.Positional = $false
            }
        }

        # Holds the new parameter names so they can be added in alphabetical order.
        $parameterNames = @()

        foreach ($currentParameter in $commandParameters.Keys)
        {
            if ($commandParameters.$currentParameter.Positional -eq $true)
            {
                continue
            }

            switch ($currentParameter)
            {
                'ActualValue'
                {
                    $parameterNames += @{
                        Actual = 'ActualValue'
                    }

                    break
                }

                default
                {
                    $parameterNames += @{
                        $currentParameter = $currentParameter
                    }

                    break
                }
            }
        }

        # This handles the named parameters in the command elements, added in alphabetical order.
        foreach ($currentParameter in $parameterNames.Keys | Sort-Object)
        {
            $originalParameterName = $parameterNames.$currentParameter

            $newExtentText += ' -{0} {1}' -f $currentParameter, $commandParameters.$originalParameterName.ExtentText
        }
    }

    Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ConvertedCommand -f $CommandAst.Extent.Text, $newExtentText)

    return $newExtentText
}
#EndRegion '.\Private\Convert-ShouldBeFalse.ps1' 187
#Region '.\Private\Convert-ShouldBeGreaterOrEqual.ps1' -1

<#
    .SYNOPSIS
        Converts a command `Should -BeGreaterOrEqual` to the specified Pester syntax.
 
    .DESCRIPTION
        The Convert-ShouldBeGreaterOrEqual function is used to convert a command `Should -BeGreaterOrEqual` to
        the specified Pester syntax.
 
    .PARAMETER CommandAst
        The CommandAst object representing the command to be converted.
 
    .PARAMETER Pester6
        Specifies that the command should be converted to Pester version 6 syntax.
 
    .PARAMETER UseNamedParameters
        Specifies whether to use named parameters in the converted syntax.
 
    .PARAMETER UsePositionalParameters
        Specifies whether to use positional parameters in the converted syntax,
        where supported.
 
    .EXAMPLE
        $commandAst = [System.Management.Automation.Language.Parser]::ParseInput('Should -BeGreaterOrEqual 2')
        Convert-ShouldBeGreaterOrEqual -CommandAst $commandAst -Pester6
 
        This example converts the `Should -BeGreaterOrEqual 2` command to Pester 6 syntax.
 
    .NOTES
        Pester 5 Syntax:
            Should -BeGreaterOrEqual [[-ActualValue] <Object>] [[-ExpectedValue] <Object>] [[-Because] <string>] [-Not]
 
            Positional parameters:
                Position 1: ExpectedValue
                Position 2: Because
                Position 3: ActualValue
 
        Pester 6 Syntax:
            Should-BeGreaterOrEqualOrEqual [[-Actual] <Object>] [-Expected] <Object> [-Because <String>]
            Should-BeLessThanOrEqual [[-Actual] <Object>] [-Expected] <Object> [-Because <String>]
 
            Positional parameters:
                Position 1: Expected
                Position 2: Actual
#>

function Convert-ShouldBeGreaterOrEqual
{
    [CmdletBinding()]
    [OutputType([System.String])]
    param
    (
        [Parameter(Mandatory = $true)]
        [System.Management.Automation.Language.CommandAst]
        $CommandAst,

        [Parameter(Mandatory = $true, ParameterSetName = 'Pester6')]
        [System.Management.Automation.SwitchParameter]
        $Pester6,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $UseNamedParameters,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $UsePositionalParameters
    )

    $assertBoundParameterParameters = @{
        BoundParameterList     = $PSBoundParameters
        MutuallyExclusiveList1 = @('UseNamedParameters')
        MutuallyExclusiveList2 = @('UsePositionalParameters')
    }

    Assert-BoundParameter @assertBoundParameterParameters

    Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ParsingCommandAst -f $CommandAst.Extent.Text)

    # Determine if the command is negated
    $isNegated = Test-PesterCommandNegated -CommandAst $CommandAst

    $sourceSyntaxVersion = Get-PesterCommandSyntaxVersion -CommandAst $CommandAst

    # Parse the command elements and convert them to Pester 6 syntax
    if ($PSCmdlet.ParameterSetName -eq 'Pester6')
    {
        Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ConvertingFromTo -f $sourceSyntaxVersion, '6')

        # Add the correct Pester command based on negation
        $newExtentText = $isNegated ? 'Should-BeLessThanOrEqual' : 'Should-BeGreaterThanOrEqual'

        $getPesterCommandParameterParameters = @{
            CommandAst          = $CommandAst
            CommandName         = 'Should'
            IgnoreParameter     = @(
                'BeGreaterOrEqual'
                'GE'
                'Not'
            )
            PositionalParameter = @(
                'ExpectedValue'
                'Because'
                'ActualValue'
            )
        }

        $commandParameters = Get-PesterCommandParameter @getPesterCommandParameterParameters

        # Parameter 'Because' is only supported as named parameter in Pester 6 syntax.
        if ($commandParameters.Because)
        {
            $commandParameters.Because.Positional = $false
        }

        # Determine if named or positional parameters should be forcibly used
        if ($UseNamedParameters.IsPresent)
        {
            $commandParameters.Keys.ForEach({ $commandParameters.$_.Positional = $false })
        }
        elseif ($UsePositionalParameters.IsPresent)
        {
            # First set all to named parameters
            $commandParameters.Keys.ForEach({ $commandParameters.$_.Positional = $false })

            <#
                If a previous positional parameter is missing then the ones behind
                it cannot be set to positional.
            #>

            if ($commandParameters.ExpectedValue)
            {
                $commandParameters.ExpectedValue.Positional = $true

                if ($commandParameters.ActualValue)
                {
                    $commandParameters.ActualValue.Positional = $true
                }
            }
        }

        $newExtentText += $commandParameters.ExpectedValue.Positional ? (' {0}' -f $commandParameters.ExpectedValue.ExtentText) : ''
        $newExtentText += $commandParameters.ActualValue.Positional ? (' {0}' -f $commandParameters.ActualValue.ExtentText) : ''

        # Holds the new parameter names so they can be added in alphabetical order.
        $parameterNames = @()

        foreach ($currentParameter in $commandParameters.Keys)
        {
            if ($commandParameters.$currentParameter.Positional -eq $true)
            {
                continue
            }

            switch ($currentParameter)
            {
                'ActualValue'
                {
                    $parameterNames += @{
                        Actual = 'ActualValue'
                    }

                    break
                }

                'ExpectedValue'
                {
                    $parameterNames += @{
                        Expected = 'ExpectedValue'
                    }

                    break
                }

                default
                {
                    $parameterNames += @{
                        $currentParameter = $currentParameter
                    }

                    break
                }
            }
        }

        # This handles the named parameters in the command elements, added in alphabetical order.
        foreach ($currentParameter in $parameterNames.Keys | Sort-Object)
        {
            $originalParameterName = $parameterNames.$currentParameter

            $newExtentText += ' -{0} {1}' -f $currentParameter, $commandParameters.$originalParameterName.ExtentText
        }
    }

    Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ConvertedCommand -f $CommandAst.Extent.Text, $newExtentText)

    return $newExtentText
}
#EndRegion '.\Private\Convert-ShouldBeGreaterOrEqual.ps1' 196
#Region '.\Private\Convert-ShouldBeGreaterThan.ps1' -1

<#
    .SYNOPSIS
        Converts a command `Should -BeGreaterThan` to the specified Pester syntax.
 
    .DESCRIPTION
        The Convert-ShouldBeGreaterThan function is used to convert a command `Should -BeGreaterThan` to
        the specified Pester syntax.
 
    .PARAMETER CommandAst
        The CommandAst object representing the command to be converted.
 
    .PARAMETER Pester6
        Specifies that the command should be converted to Pester version 6 syntax.
 
    .PARAMETER UseNamedParameters
        Specifies whether to use named parameters in the converted syntax.
 
    .PARAMETER UsePositionalParameters
        Specifies whether to use positional parameters in the converted syntax,
        where supported.
 
    .EXAMPLE
        $commandAst = [System.Management.Automation.Language.Parser]::ParseInput('Should -BeGreaterThan 2')
        Convert-ShouldBeGreaterThan -CommandAst $commandAst -Pester6
 
        This example converts the `Should -BeGreaterThan 2` command to Pester 6 syntax.
 
    .NOTES
        Pester 5 Syntax:
            Should -BeGreaterThan [[-ActualValue] <Object>] [[-ExpectedValue] <Object>] [[-Because] <string>] [-Not]
 
            Positional parameters:
                Position 1: ExpectedValue
                Position 2: Because
                Position 3: ActualValue
 
        Pester 6 Syntax:
            Should-BeGreaterThan [[-Actual] <Object>] [-Expected] <Object> [-Because <String>]
            Should-BeLessThanOrEqual [[-Actual] <Object>] [-Expected] <Object> [-Because <String>]
 
            Positional parameters:
                Position 1: Expected
                Position 2: Actual
 
        Conversion notes:
            If the command is negated, the `Should-BeLessThanOrEqual` command is used.
            Assume the actual value is 2 and the expected value should not be greater
            than 2, then we need to use the `Should-BeLessThanOrEqual` command for
            the logic to be the same:
                Pester 5: 2 | Should -Not -BeGreaterThan 2
                Pester 6: 2 | Should-BeLessThanOrEqual 2
#>

function Convert-ShouldBeGreaterThan
{
    [CmdletBinding()]
    [OutputType([System.String])]
    param
    (
        [Parameter(Mandatory = $true)]
        [System.Management.Automation.Language.CommandAst]
        $CommandAst,

        [Parameter(Mandatory = $true, ParameterSetName = 'Pester6')]
        [System.Management.Automation.SwitchParameter]
        $Pester6,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $UseNamedParameters,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $UsePositionalParameters
    )

    $assertBoundParameterParameters = @{
        BoundParameterList     = $PSBoundParameters
        MutuallyExclusiveList1 = @('UseNamedParameters')
        MutuallyExclusiveList2 = @('UsePositionalParameters')
    }

    Assert-BoundParameter @assertBoundParameterParameters

    Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ParsingCommandAst -f $CommandAst.Extent.Text)

    # Determine if the command is negated
    $isNegated = Test-PesterCommandNegated -CommandAst $CommandAst

    $sourceSyntaxVersion = Get-PesterCommandSyntaxVersion -CommandAst $CommandAst

    # Parse the command elements and convert them to Pester 6 syntax
    if ($PSCmdlet.ParameterSetName -eq 'Pester6')
    {
        Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ConvertingFromTo -f $sourceSyntaxVersion, '6')

        # Add the correct Pester command based on negation
        $newExtentText = $isNegated ? 'Should-BeLessThanOrEqual' : 'Should-BeGreaterThan'

        $getPesterCommandParameterParameters = @{
            CommandAst          = $CommandAst
            CommandName         = 'Should'
            IgnoreParameter     = @(
                'BeGreaterThan'
                'GT'
                'Not'
            )
            PositionalParameter = @(
                'ExpectedValue'
                'Because'
                'ActualValue'
            )
        }

        $commandParameters = Get-PesterCommandParameter @getPesterCommandParameterParameters

        # Parameter 'Because' is only supported as named parameter in Pester 6 syntax.
        if ($commandParameters.Because)
        {
            $commandParameters.Because.Positional = $false
        }

        # Determine if named or positional parameters should be forcibly used
        if ($UseNamedParameters.IsPresent)
        {
            $commandParameters.Keys.ForEach({ $commandParameters.$_.Positional = $false })
        }
        elseif ($UsePositionalParameters.IsPresent)
        {
            # First set all to named parameters
            $commandParameters.Keys.ForEach({ $commandParameters.$_.Positional = $false })

            <#
                If a previous positional parameter is missing then the ones behind
                it cannot be set to positional.
            #>

            if ($commandParameters.ExpectedValue)
            {
                $commandParameters.ExpectedValue.Positional = $true

                if ($commandParameters.ActualValue)
                {
                    $commandParameters.ActualValue.Positional = $true
                }
            }
        }

        $newExtentText += $commandParameters.ExpectedValue.Positional ? (' {0}' -f $commandParameters.ExpectedValue.ExtentText) : ''
        $newExtentText += $commandParameters.ActualValue.Positional ? (' {0}' -f $commandParameters.ActualValue.ExtentText) : ''

        # Holds the new parameter names so they can be added in alphabetical order.
        $parameterNames = @()

        foreach ($currentParameter in $commandParameters.Keys)
        {
            if ($commandParameters.$currentParameter.Positional -eq $true)
            {
                continue
            }

            switch ($currentParameter)
            {
                'ActualValue'
                {
                    $parameterNames += @{
                        Actual = 'ActualValue'
                    }

                    break
                }

                'ExpectedValue'
                {
                    $parameterNames += @{
                        Expected = 'ExpectedValue'
                    }

                    break
                }

                default
                {
                    $parameterNames += @{
                        $currentParameter = $currentParameter
                    }

                    break
                }
            }
        }

        # This handles the named parameters in the command elements, added in alphabetical order.
        foreach ($currentParameter in $parameterNames.Keys | Sort-Object)
        {
            $originalParameterName = $parameterNames.$currentParameter

            $newExtentText += ' -{0} {1}' -f $currentParameter, $commandParameters.$originalParameterName.ExtentText
        }
    }

    Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ConvertedCommand -f $CommandAst.Extent.Text, $newExtentText)

    return $newExtentText
}
#EndRegion '.\Private\Convert-ShouldBeGreaterThan.ps1' 204
#Region '.\Private\Convert-ShouldBeIn.ps1' -1

<#
    .SYNOPSIS
        Converts a command `Should -BeIn` to the specified Pester syntax.
 
    .DESCRIPTION
        The Convert-ShouldContain function is used to convert a command `Should -BeIn` to
        the specified Pester syntax.
 
    .PARAMETER CommandAst
        The CommandAst object representing the command to be converted.
 
    .PARAMETER Pester6
        Specifies that the command should be converted to Pester version 6 syntax.
 
    .PARAMETER UseNamedParameters
        Specifies whether to use named parameters in the converted syntax.
 
    .PARAMETER UsePositionalParameters
        Specifies whether to use positional parameters in the converted syntax,
        where supported.
 
    .EXAMPLE
        $commandAst = [System.Management.Automation.Language.Parser]::ParseInput('Should -BeIn @("Test", "Test2")')
        Convert-ShouldContain -CommandAst $commandAst -Pester6
 
        This example converts the `Should -BeIn @("Test", "Test2")` command to Pester 6 syntax.
 
    .NOTES
        Pester 5 Syntax:
            Should -BeIn [[-ActualValue] <Object>] [[-ExpectedValue] <Object>] [[-Because] <string>] [-Not]
 
            Positional parameters:
                Position 1: ExpectedValue
                Position 2: Because
                Position 3: ActualValue
 
        Pester 6 Syntax:
            Should-ContainCollection [-Actual] <Object>] [-Expected] <Object> [-Because <String>]
            Should-NotContainCollection [[-Actual] <Object>] [-Expected] <Object> [-Because <String>]
 
            Positional parameters:
                Position 1: Expected
                Position 2: Actual
#>

function Convert-ShouldBeIn
{
    [CmdletBinding()]
    [OutputType([System.String])]
    param
    (
        [Parameter(Mandatory = $true)]
        [System.Management.Automation.Language.CommandAst]
        $CommandAst,

        [Parameter(Mandatory = $true, ParameterSetName = 'Pester6')]
        [System.Management.Automation.SwitchParameter]
        $Pester6,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $UseNamedParameters,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $UsePositionalParameters
    )

    $assertBoundParameterParameters = @{
        BoundParameterList     = $PSBoundParameters
        MutuallyExclusiveList1 = @('UseNamedParameters')
        MutuallyExclusiveList2 = @('UsePositionalParameters')
    }

    Assert-BoundParameter @assertBoundParameterParameters

    Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ParsingCommandAst -f $CommandAst.Extent.Text)

    # Determine if the command is negated
    $isNegated = Test-PesterCommandNegated -CommandAst $CommandAst

    $sourceSyntaxVersion = Get-PesterCommandSyntaxVersion -CommandAst $CommandAst

    # Parse the command elements and convert them to Pester 6 syntax
    if ($PSCmdlet.ParameterSetName -eq 'Pester6')
    {
        Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ConvertingFromTo -f $sourceSyntaxVersion, '6')

        # Add the correct Pester command based on negation
        $newExtentText = $isNegated ? 'Should-NotContainCollection' : 'Should-ContainCollection'

        $getPesterCommandParameterParameters = @{
            CommandAst          = $CommandAst
            CommandName         = 'Should'
            IgnoreParameter     = @(
                'BeIn'
                'Not'
            )
            PositionalParameter = @(
                'ExpectedValue'
                'Because'
                'ActualValue'
            )
            NamedParameter      = @()
        }

        $commandParameters = Get-PesterCommandParameter @getPesterCommandParameterParameters

        $pipelineExtentText = Get-PipelineBeforeShould -CommandAst $CommandAst -ParsePipeline

        # NOTE! This switches the arguments between expected and actual values.
        $originalActualValue = $commandParameters.ActualValue
        $commandParameters.ActualValue = $commandParameters.ExpectedValue
        $commandParameters.ExpectedValue = $originalActualValue

        # If we do not end up with a value for ExpectValue we need to get it from the pipeline.
        $isPipeline = $null -eq $commandParameters.ExpectedValue

        if ($isPipeline)
        {
            <#
                ActualValue was not part of the arguments as either positional or
                named parameter, assume there is a pipeline and the original
                ActualValue should be converted to Expected. Also using the
                position and positional property values from original ActualValue
                for the new ExpectedValue.
            #>

            $commandParameters.ExpectedValue = @{
                Position   = $commandParameters.ActualValue.Position
                Positional = $commandParameters.ActualValue.Positional
                ExtentText = '({0})' -f $pipelineExtentText
            }

            <#
                We must put the new actual value on the pipeline before the Should
                command, so we need to make sure it is not added as positional.
            #>

            $commandParameters.ActualValue.Position = 0
            $commandParameters.ActualValue.Positional = $false
        }

        # Parameter 'Because' is only supported as named parameter in Pester 6 syntax.
        if ($commandParameters.Because)
        {
            $commandParameters.Because.Positional = $false
        }

        # Determine if named or positional parameters should be forcibly used
        if ($UseNamedParameters.IsPresent)
        {
            $commandParameters.Keys.ForEach({ $commandParameters.$_.Positional = $false })
        }
        elseif ($UsePositionalParameters.IsPresent)
        {
            # First set all to named parameters
            $commandParameters.Keys.ForEach({ $commandParameters.$_.Positional = $false })

            <#
                If a previous positional parameter is missing then the ones behind
                it cannot be set to positional.
            #>

            if ($commandParameters.ExpectedValue)
            {
                $commandParameters.ExpectedValue.Positional = $true

                # If the actual value was originally passed in the pipeline, we should do the same.
                if ($commandParameters.ActualValue -and -not $isPipeline)
                {
                    $commandParameters.ActualValue.Positional = $true
                }
            }
        }

        $newExtentText += $commandParameters.ExpectedValue.Positional ? (' {0}' -f $commandParameters.ExpectedValue.ExtentText) : ''
        $newExtentText += $commandParameters.ActualValue.Positional ? (' {0}' -f $commandParameters.ActualValue.ExtentText) : ''

        # Holds the new parameter names so they can be added in alphabetical order.
        $parameterNames = @()

        foreach ($currentParameter in $commandParameters.Keys)
        {
            if ($commandParameters.$currentParameter.Positional -eq $true)
            {
                continue
            }

            switch ($currentParameter)
            {
                'ActualValue'
                {
                    if ($isPipeline)
                    {
                        continue
                    }

                    $parameterNames += @{
                        Actual = 'ActualValue'
                    }

                    break
                }

                'ExpectedValue'
                {
                    $parameterNames += @{
                        Expected = 'ExpectedValue'
                    }

                    break
                }

                default
                {
                    $parameterNames += @{
                        $currentParameter = $currentParameter
                    }

                    break
                }
            }
        }

        # This handles the named parameters in the command elements, added in alphabetical order.
        foreach ($currentParameter in $parameterNames.Keys | Sort-Object)
        {
            $originalParameterName = $parameterNames.$currentParameter

            $newExtentText += ' -{0} {1}' -f $currentParameter, $commandParameters.$originalParameterName.ExtentText
        }
    }

    if ($isPipeline)
    {
        $newExtentText = '{0} | {1}' -f $commandParameters.ActualValue.ExtentText, $newExtentText
    }

    Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ConvertedCommand -f $CommandAst.Extent.Text, $newExtentText)

    return $newExtentText
}
#EndRegion '.\Private\Convert-ShouldBeIn.ps1' 240
#Region '.\Private\Convert-ShouldBeLessOrEqual.ps1' -1

<#
    .SYNOPSIS
        Converts a command `Should -BeLessOrEqual` to the specified Pester syntax.
 
    .DESCRIPTION
        The Convert-ShouldBeLessOrEqual function is used to convert a command `Should -BeLessOrEqual` to
        the specified Pester syntax.
 
    .PARAMETER CommandAst
        The CommandAst object representing the command to be converted.
 
    .PARAMETER Pester6
        Specifies that the command should be converted to Pester version 6 syntax.
 
    .PARAMETER UseNamedParameters
        Specifies whether to use named parameters in the converted syntax.
 
    .PARAMETER UsePositionalParameters
        Specifies whether to use positional parameters in the converted syntax,
        where supported.
 
    .EXAMPLE
        $commandAst = [System.Management.Automation.Language.Parser]::ParseInput('Should -BeLessOrEqual 2')
        Convert-ShouldBeLessOrEqual -CommandAst $commandAst -Pester6
 
        This example converts the `Should -BeLessOrEqual 2` command to Pester 6 syntax.
 
    .NOTES
        Pester 5 Syntax:
            Should -BeLessOrEqual [[-ActualValue] <Object>] [[-ExpectedValue] <Object>] [[-Because] <string>] [-Not]
 
            Positional parameters:
                Position 1: ExpectedValue
                Position 2: Because
                Position 3: ActualValue
 
        Pester 6 Syntax:
            Should-BeLessOrEqualOrEqual [[-Actual] <Object>] [-Expected] <Object> [-Because <String>]
            Should-BeLessThanOrEqual [[-Actual] <Object>] [-Expected] <Object> [-Because <String>]
 
            Positional parameters:
                Position 1: Expected
                Position 2: Actual
#>

function Convert-ShouldBeLessOrEqual
{
    [CmdletBinding()]
    [OutputType([System.String])]
    param
    (
        [Parameter(Mandatory = $true)]
        [System.Management.Automation.Language.CommandAst]
        $CommandAst,

        [Parameter(Mandatory = $true, ParameterSetName = 'Pester6')]
        [System.Management.Automation.SwitchParameter]
        $Pester6,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $UseNamedParameters,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $UsePositionalParameters
    )

    $assertBoundParameterParameters = @{
        BoundParameterList     = $PSBoundParameters
        MutuallyExclusiveList1 = @('UseNamedParameters')
        MutuallyExclusiveList2 = @('UsePositionalParameters')
    }

    Assert-BoundParameter @assertBoundParameterParameters

    Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ParsingCommandAst -f $CommandAst.Extent.Text)

    # Determine if the command is negated
    $isNegated = Test-PesterCommandNegated -CommandAst $CommandAst

    $sourceSyntaxVersion = Get-PesterCommandSyntaxVersion -CommandAst $CommandAst

    # Parse the command elements and convert them to Pester 6 syntax
    if ($PSCmdlet.ParameterSetName -eq 'Pester6')
    {
        Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ConvertingFromTo -f $sourceSyntaxVersion, '6')

        # Add the correct Pester command based on negation
        $newExtentText = $isNegated ? 'Should-BeGreaterThanOrEqual': 'Should-BeLessThanOrEqual'

        $getPesterCommandParameterParameters = @{
            CommandAst          = $CommandAst
            CommandName         = 'Should'
            IgnoreParameter     = @(
                'BeLessOrEqual'
                'LE'
                'Not'
            )
            PositionalParameter = @(
                'ExpectedValue'
                'Because'
                'ActualValue'
            )
        }

        $commandParameters = Get-PesterCommandParameter @getPesterCommandParameterParameters

        # Parameter 'Because' is only supported as named parameter in Pester 6 syntax.
        if ($commandParameters.Because)
        {
            $commandParameters.Because.Positional = $false
        }

        # Determine if named or positional parameters should be forcibly used
        if ($UseNamedParameters.IsPresent)
        {
            $commandParameters.Keys.ForEach({ $commandParameters.$_.Positional = $false })
        }
        elseif ($UsePositionalParameters.IsPresent)
        {
            # First set all to named parameters
            $commandParameters.Keys.ForEach({ $commandParameters.$_.Positional = $false })

            <#
                If a previous positional parameter is missing then the ones behind
                it cannot be set to positional.
            #>

            if ($commandParameters.ExpectedValue)
            {
                $commandParameters.ExpectedValue.Positional = $true

                if ($commandParameters.ActualValue)
                {
                    $commandParameters.ActualValue.Positional = $true
                }
            }
        }

        $newExtentText += $commandParameters.ExpectedValue.Positional ? (' {0}' -f $commandParameters.ExpectedValue.ExtentText) : ''
        $newExtentText += $commandParameters.ActualValue.Positional ? (' {0}' -f $commandParameters.ActualValue.ExtentText) : ''

        # Holds the new parameter names so they can be added in alphabetical order.
        $parameterNames = @()

        foreach ($currentParameter in $commandParameters.Keys)
        {
            if ($commandParameters.$currentParameter.Positional -eq $true)
            {
                continue
            }

            switch ($currentParameter)
            {
                'ActualValue'
                {
                    $parameterNames += @{
                        Actual = 'ActualValue'
                    }

                    break
                }

                'ExpectedValue'
                {
                    $parameterNames += @{
                        Expected = 'ExpectedValue'
                    }

                    break
                }

                default
                {
                    $parameterNames += @{
                        $currentParameter = $currentParameter
                    }

                    break
                }
            }
        }

        # This handles the named parameters in the command elements, added in alphabetical order.
        foreach ($currentParameter in $parameterNames.Keys | Sort-Object)
        {
            $originalParameterName = $parameterNames.$currentParameter

            $newExtentText += ' -{0} {1}' -f $currentParameter, $commandParameters.$originalParameterName.ExtentText
        }
    }

    Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ConvertedCommand -f $CommandAst.Extent.Text, $newExtentText)

    return $newExtentText
}
#EndRegion '.\Private\Convert-ShouldBeLessOrEqual.ps1' 196
#Region '.\Private\Convert-ShouldBeLessThan.ps1' -1

<#
    .SYNOPSIS
        Converts a command `Should -BeLessThan` to the specified Pester syntax.
 
    .DESCRIPTION
        The Convert-ShouldBeLessThan function is used to convert a command `Should -BeLessThan` to
        the specified Pester syntax.
 
    .PARAMETER CommandAst
        The CommandAst object representing the command to be converted.
 
    .PARAMETER Pester6
        Specifies that the command should be converted to Pester version 6 syntax.
 
    .PARAMETER UseNamedParameters
        Specifies whether to use named parameters in the converted syntax.
 
    .PARAMETER UsePositionalParameters
        Specifies whether to use positional parameters in the converted syntax,
        where supported.
 
    .EXAMPLE
        $commandAst = [System.Management.Automation.Language.Parser]::ParseInput('Should -BeLessThan 2')
        Convert-ShouldBeLessThan -CommandAst $commandAst -Pester6
 
        This example converts the `Should -BeLessThan 2` command to Pester 6 syntax.
 
    .NOTES
        Pester 5 Syntax:
            Should -BeLessThan [[-ActualValue] <Object>] [[-ExpectedValue] <Object>] [[-Because] <string>] [-Not]
 
            Positional parameters:
                Position 1: ExpectedValue
                Position 2: Because
                Position 3: ActualValue
 
        Pester 6 Syntax:
            Should-BeLessThan [[-Actual] <Object>] [-Expected] <Object> [-Because <String>]
            Should-BeGreaterThanOrEqual [[-Actual] <Object>] [-Expected] <Object> [-Because <String>]
 
            Positional parameters:
                Position 1: Expected
                Position 2: Actual
 
        Conversion notes:
            If the command is negated, the `Should-BeGreaterThanOrEqual` command is
            used. Assume the actual value is 2 and the expected value should not be
            less than 2, then we need to use the `Should-BeLessThanOrEqual` command
            for the logic to be the same:
                Pester 5: 2 | Should -Not -BeLessThan 2
                Pester 6: 2 | Should-BeGreaterThanOrEqual 2
#>

function Convert-ShouldBeLessThan
{
    [CmdletBinding()]
    [OutputType([System.String])]
    param
    (
        [Parameter(Mandatory = $true)]
        [System.Management.Automation.Language.CommandAst]
        $CommandAst,

        [Parameter(Mandatory = $true, ParameterSetName = 'Pester6')]
        [System.Management.Automation.SwitchParameter]
        $Pester6,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $UseNamedParameters,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $UsePositionalParameters
    )

    $assertBoundParameterParameters = @{
        BoundParameterList     = $PSBoundParameters
        MutuallyExclusiveList1 = @('UseNamedParameters')
        MutuallyExclusiveList2 = @('UsePositionalParameters')
    }

    Assert-BoundParameter @assertBoundParameterParameters

    Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ParsingCommandAst -f $CommandAst.Extent.Text)

    # Determine if the command is negated
    $isNegated = Test-PesterCommandNegated -CommandAst $CommandAst

    $sourceSyntaxVersion = Get-PesterCommandSyntaxVersion -CommandAst $CommandAst

    # Parse the command elements and convert them to Pester 6 syntax
    if ($PSCmdlet.ParameterSetName -eq 'Pester6')
    {
        Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ConvertingFromTo -f $sourceSyntaxVersion, '6')

        # Add the correct Pester command based on negation
        $newExtentText = $isNegated ? 'Should-BeGreaterThanOrEqual' : 'Should-BeLessThan'

        $getPesterCommandParameterParameters = @{
            CommandAst          = $CommandAst
            CommandName         = 'Should'
            IgnoreParameter     = @(
                'BeLessThan'
                'LT'
                'Not'
            )
            PositionalParameter = @(
                'ExpectedValue'
                'Because'
                'ActualValue'
            )
        }

        $commandParameters = Get-PesterCommandParameter @getPesterCommandParameterParameters

        # Parameter 'Because' is only supported as named parameter in Pester 6 syntax.
        if ($commandParameters.Because)
        {
            $commandParameters.Because.Positional = $false
        }

        # Determine if named or positional parameters should be forcibly used
        if ($UseNamedParameters.IsPresent)
        {
            $commandParameters.Keys.ForEach({ $commandParameters.$_.Positional = $false })
        }
        elseif ($UsePositionalParameters.IsPresent)
        {
            # First set all to named parameters
            $commandParameters.Keys.ForEach({ $commandParameters.$_.Positional = $false })

            <#
                If a previous positional parameter is missing then the ones behind
                it cannot be set to positional.
            #>

            if ($commandParameters.ExpectedValue)
            {
                $commandParameters.ExpectedValue.Positional = $true

                if ($commandParameters.ActualValue)
                {
                    $commandParameters.ActualValue.Positional = $true
                }
            }
        }

        $newExtentText += $commandParameters.ExpectedValue.Positional ? (' {0}' -f $commandParameters.ExpectedValue.ExtentText) : ''
        $newExtentText += $commandParameters.ActualValue.Positional ? (' {0}' -f $commandParameters.ActualValue.ExtentText) : ''

        # Holds the new parameter names so they can be added in alphabetical order.
        $parameterNames = @()

        foreach ($currentParameter in $commandParameters.Keys)
        {
            if ($commandParameters.$currentParameter.Positional -eq $true)
            {
                continue
            }

            switch ($currentParameter)
            {
                'ActualValue'
                {
                    $parameterNames += @{
                        Actual = 'ActualValue'
                    }

                    break
                }

                'ExpectedValue'
                {
                    $parameterNames += @{
                        Expected = 'ExpectedValue'
                    }

                    break
                }

                default
                {
                    $parameterNames += @{
                        $currentParameter = $currentParameter
                    }

                    break
                }
            }
        }

        # This handles the named parameters in the command elements, added in alphabetical order.
        foreach ($currentParameter in $parameterNames.Keys | Sort-Object)
        {
            $originalParameterName = $parameterNames.$currentParameter

            $newExtentText += ' -{0} {1}' -f $currentParameter, $commandParameters.$originalParameterName.ExtentText
        }
    }

    Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ConvertedCommand -f $CommandAst.Extent.Text, $newExtentText)

    return $newExtentText
}
#EndRegion '.\Private\Convert-ShouldBeLessThan.ps1' 204
#Region '.\Private\Convert-ShouldBeLike.ps1' -1

<#
    .SYNOPSIS
        Converts a command `Should -BeLike` to the specified Pester syntax.
 
    .DESCRIPTION
        The Convert-ShouldBeLike function is used to convert a command `Should -BeLike` to
        the specified Pester syntax.
 
    .PARAMETER CommandAst
        The CommandAst object representing the command to be converted.
 
    .PARAMETER Pester6
        Specifies that the command should be converted to Pester version 6 syntax.
 
    .PARAMETER UseNamedParameters
        Specifies whether to use named parameters in the converted syntax.
 
    .PARAMETER UsePositionalParameters
        Specifies whether to use positional parameters in the converted syntax,
        where supported.
 
    .EXAMPLE
        $commandAst = [System.Management.Automation.Language.Parser]::ParseInput('Should -BeLike "Test*"')
        Convert-ShouldBeLike -CommandAst $commandAst -Pester6
 
        This example converts the `Should -BeLike "Test*"` command to Pester 6 syntax.
 
    .NOTES
        Pester 5 Syntax:
            Should -BeLike [[-ActualValue] <Object>] [[-ExpectedValue] <Object>] [[-Because] <string>] [-Not]
 
            Positional parameters:
                Position 1: ExpectedValue
                Position 2: Because
                Position 3: ActualValue
 
        Pester 6 Syntax:
            Should-BeLikeString [[-Actual] <Object>] [-Expected] <String> [-CaseSensitive] [-Because <String>]
            Should-NotBeLikeString [[-Actual] <Object>] [-Expected] <String> [-CaseSensitive] [-Because <String>]
 
            Positional parameters:
                Position 1: Expected
                Position 2: Actual
#>

function Convert-ShouldBeLike
{
    [CmdletBinding()]
    [OutputType([System.String])]
    param
    (
        [Parameter(Mandatory = $true)]
        [System.Management.Automation.Language.CommandAst]
        $CommandAst,

        [Parameter(Mandatory = $true, ParameterSetName = 'Pester6')]
        [System.Management.Automation.SwitchParameter]
        $Pester6,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $UseNamedParameters,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $UsePositionalParameters
    )

    $assertBoundParameterParameters = @{
        BoundParameterList     = $PSBoundParameters
        MutuallyExclusiveList1 = @('UseNamedParameters')
        MutuallyExclusiveList2 = @('UsePositionalParameters')
    }

    Assert-BoundParameter @assertBoundParameterParameters

    Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ParsingCommandAst -f $CommandAst.Extent.Text)

    # Determine if the command is negated
    $isNegated = Test-PesterCommandNegated -CommandAst $CommandAst

    $sourceSyntaxVersion = Get-PesterCommandSyntaxVersion -CommandAst $CommandAst

    # Parse the command elements and convert them to Pester 6 syntax
    if ($PSCmdlet.ParameterSetName -eq 'Pester6')
    {
        Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ConvertingFromTo -f $sourceSyntaxVersion, '6')

        # Add the correct Pester command based on negation
        $newExtentText = $isNegated ? 'Should-NotBeLikeString' : 'Should-BeLikeString'

        $getPesterCommandParameterParameters = @{
            CommandAst          = $CommandAst
            CommandName         = 'Should'
            IgnoreParameter     = @(
                'BeLike'
                'Not'
            )
            PositionalParameter = @(
                'ExpectedValue'
                'Because'
                'ActualValue'
            )
        }

        $commandParameters = Get-PesterCommandParameter @getPesterCommandParameterParameters

        # Parameter 'Because' is only supported as named parameter in Pester 6 syntax.
        if ($commandParameters.Because)
        {
            $commandParameters.Because.Positional = $false
        }

        # Determine if named or positional parameters should be forcibly used
        if ($UseNamedParameters.IsPresent)
        {
            $commandParameters.Keys.ForEach({ $commandParameters.$_.Positional = $false })
        }
        elseif ($UsePositionalParameters.IsPresent)
        {
            # First set all to named parameters
            $commandParameters.Keys.ForEach({ $commandParameters.$_.Positional = $false })

            <#
                If a previous positional parameter is missing then the ones behind
                it cannot be set to positional.
            #>

            if ($commandParameters.ExpectedValue)
            {
                $commandParameters.ExpectedValue.Positional = $true

                if ($commandParameters.ActualValue)
                {
                    $commandParameters.ActualValue.Positional = $true
                }
            }
        }

        $newExtentText += $commandParameters.ExpectedValue.Positional ? (' {0}' -f $commandParameters.ExpectedValue.ExtentText) : ''
        $newExtentText += $commandParameters.ActualValue.Positional ? (' {0}' -f $commandParameters.ActualValue.ExtentText) : ''

        # Holds the new parameter names so they can be added in alphabetical order.
        $parameterNames = @()

        foreach ($currentParameter in $commandParameters.Keys)
        {
            if ($commandParameters.$currentParameter.Positional -eq $true)
            {
                continue
            }

            switch ($currentParameter)
            {
                'ActualValue'
                {
                    $parameterNames += @{
                        Actual = 'ActualValue'
                    }

                    break
                }

                'ExpectedValue'
                {
                    $parameterNames += @{
                        Expected = 'ExpectedValue'
                    }

                    break
                }

                default
                {
                    $parameterNames += @{
                        $currentParameter = $currentParameter
                    }

                    break
                }
            }
        }

        # This handles the named parameters in the command elements, added in alphabetical order.
        foreach ($currentParameter in $parameterNames.Keys | Sort-Object)
        {
            $originalParameterName = $parameterNames.$currentParameter

            $newExtentText += ' -{0} {1}' -f $currentParameter, $commandParameters.$originalParameterName.ExtentText
        }
    }

    Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ConvertedCommand -f $CommandAst.Extent.Text, $newExtentText)

    return $newExtentText
}
#EndRegion '.\Private\Convert-ShouldBeLike.ps1' 195
#Region '.\Private\Convert-ShouldBeLikeExactly.ps1' -1

<#
    .SYNOPSIS
        Converts a command `Should -BeLikeExactly` to the specified Pester syntax.
 
    .DESCRIPTION
        The Convert-ShouldBeLikeExactly function is used to convert a command `Should -BeLikeExactly` to
        the specified Pester syntax.
 
    .PARAMETER CommandAst
        The CommandAst object representing the command to be converted.
 
    .PARAMETER Pester6
        Specifies that the command should be converted to Pester version 6 syntax.
 
    .PARAMETER UseNamedParameters
        Specifies whether to use named parameters in the converted syntax.
 
    .PARAMETER UsePositionalParameters
        Specifies whether to use positional parameters in the converted syntax,
        where supported.
 
    .EXAMPLE
        $commandAst = [System.Management.Automation.Language.Parser]::ParseInput('Should -BeLikeExactly "Test*"')
        Convert-ShouldBeLikeExactly -CommandAst $commandAst -Pester6
 
        This example converts the `Should -BeLikeExactly "Test*"` command to Pester 6 syntax.
 
    .NOTES
        Pester 5 Syntax:
            Should -BeLikeExactly [[-ActualValue] <Object>] [[-ExpectedValue] <Object>] [[-Because] <string>] [-Not]
 
            Positional parameters:
                Position 1: ExpectedValue
                Position 2: Because
                Position 3: ActualValue
 
        Pester 6 Syntax:
            Should-BeLikeString [[-Actual] <Object>] [-Expected] <String> [-CaseSensitive] [-Because <String>]
            Should-NotBeLikeString [[-Actual] <Object>] [-Expected] <String> [-CaseSensitive] [-Because <String>]
 
            Positional parameters:
                Position 1: Expected
                Position 2: Actual
#>

function Convert-ShouldBeLikeExactly
{
    [CmdletBinding()]
    [OutputType([System.String])]
    param
    (
        [Parameter(Mandatory = $true)]
        [System.Management.Automation.Language.CommandAst]
        $CommandAst,

        [Parameter(Mandatory = $true, ParameterSetName = 'Pester6')]
        [System.Management.Automation.SwitchParameter]
        $Pester6,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $UseNamedParameters,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $UsePositionalParameters
    )

    $assertBoundParameterParameters = @{
        BoundParameterList     = $PSBoundParameters
        MutuallyExclusiveList1 = @('UseNamedParameters')
        MutuallyExclusiveList2 = @('UsePositionalParameters')
    }

    Assert-BoundParameter @assertBoundParameterParameters

    Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ParsingCommandAst -f $CommandAst.Extent.Text)

    # Determine if the command is negated
    $isNegated = Test-PesterCommandNegated -CommandAst $CommandAst

    $sourceSyntaxVersion = Get-PesterCommandSyntaxVersion -CommandAst $CommandAst

    # Parse the command elements and convert them to Pester 6 syntax
    if ($PSCmdlet.ParameterSetName -eq 'Pester6')
    {
        Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ConvertingFromTo -f $sourceSyntaxVersion, '6')

        # Add the correct Pester command based on negation
        $newExtentText = $isNegated ? 'Should-NotBeLikeString' : 'Should-BeLikeString'

        # Always add the `-CaseSensitive` parameter since MatchExactly was case-sensitive.
        $newExtentText += ' -CaseSensitive'

        $getPesterCommandParameterParameters = @{
            CommandAst          = $CommandAst
            CommandName         = 'Should'
            IgnoreParameter     = @(
                'BeLikeExactly'
                'Not'
            )
            PositionalParameter = @(
                'ExpectedValue'
                'Because'
                'ActualValue'
            )
        }

        $commandParameters = Get-PesterCommandParameter @getPesterCommandParameterParameters

        # Parameter 'Because' is only supported as named parameter in Pester 6 syntax.
        if ($commandParameters.Because)
        {
            $commandParameters.Because.Positional = $false
        }

        # Determine if named or positional parameters should be forcibly used
        if ($UseNamedParameters.IsPresent)
        {
            $commandParameters.Keys.ForEach({ $commandParameters.$_.Positional = $false })
        }
        elseif ($UsePositionalParameters.IsPresent)
        {
            # First set all to named parameters
            $commandParameters.Keys.ForEach({ $commandParameters.$_.Positional = $false })

            <#
                If a previous positional parameter is missing then the ones behind
                it cannot be set to positional.
            #>

            if ($commandParameters.ExpectedValue)
            {
                $commandParameters.ExpectedValue.Positional = $true

                if ($commandParameters.ActualValue)
                {
                    $commandParameters.ActualValue.Positional = $true
                }
            }
        }

        $newExtentText += $commandParameters.ExpectedValue.Positional ? (' {0}' -f $commandParameters.ExpectedValue.ExtentText) : ''
        $newExtentText += $commandParameters.ActualValue.Positional ? (' {0}' -f $commandParameters.ActualValue.ExtentText) : ''

        # Holds the new parameter names so they can be added in alphabetical order.
        $parameterNames = @()

        foreach ($currentParameter in $commandParameters.Keys)
        {
            if ($commandParameters.$currentParameter.Positional -eq $true)
            {
                continue
            }

            switch ($currentParameter)
            {
                'ActualValue'
                {
                    $parameterNames += @{
                        Actual = 'ActualValue'
                    }

                    break
                }

                'ExpectedValue'
                {
                    $parameterNames += @{
                        Expected = 'ExpectedValue'
                    }

                    break
                }

                default
                {
                    $parameterNames += @{
                        $currentParameter = $currentParameter
                    }

                    break
                }
            }
        }

        # This handles the named parameters in the command elements, added in alphabetical order.
        foreach ($currentParameter in $parameterNames.Keys | Sort-Object)
        {
            $originalParameterName = $parameterNames.$currentParameter

            $newExtentText += ' -{0} {1}' -f $currentParameter, $commandParameters.$originalParameterName.ExtentText
        }
    }

    Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ConvertedCommand -f $CommandAst.Extent.Text, $newExtentText)

    return $newExtentText
}
#EndRegion '.\Private\Convert-ShouldBeLikeExactly.ps1' 198
#Region '.\Private\Convert-ShouldBeNullOrEmpty.ps1' -1

<#
    .SYNOPSIS
        Converts a command `Should -BeNullOrEmpty` to the specified Pester syntax.
 
    .DESCRIPTION
        The Convert-ShouldBeNullOrEmpty function is used to convert a command
        `Should -BeNullOrEmpty` to the specified Pester syntax.
 
    .PARAMETER CommandAst
        The CommandAst object representing the command to be converted.
 
    .PARAMETER Pester6
        Specifies that the command should be converted to Pester version 6 syntax.
 
    .PARAMETER UseNamedParameters
        Specifies whether to use named parameters in the converted syntax.
 
    .PARAMETER UsePositionalParameters
        Specifies whether to use positional parameters in the converted syntax,
        where supported.
 
    .EXAMPLE
        $commandAst = [System.Management.Automation.Language.Parser]::ParseInput('Should -BeNullOrEmpty')
        Convert-ShouldBeNullOrEmpty -CommandAst $commandAst -Pester6
 
        This example converts the `Should -BeNullOrEmpty` command to Pester 6 syntax.
 
    .NOTES
        Pester 5 Syntax:
            Should -BeNullOrEmpty [[-ActualValue] <Object>] [[-Because] <string>] [-Not]
 
            Positional parameters:
                Position 1: Because
                Position 2: ActualValue
 
        Pester 6 Syntax:
            Should-BeFalsy [[-Actual] <Object>] [[-Because] <String>]
            Should-BeTruthy [[-Actual] <Object>] [[-Because] <String>]
 
            Positional parameters:
                Position 1: Actual
                Position 2: Because
 
        Conversion notes:
            If the Pester 5 syntax is negated it must be converted to Should-BeTruthy.
 
            If the Pester 5 syntax uses positional parameters, the conversion must
            convert position 1 to position 2 and vice versa.
 
            It should output informational message that the user should review the
            converted commands to evaluate if it should stay Should-BeFalsy or if
            Should-BeNull or Should-BeEmptyString should be used instead.
#>

function Convert-ShouldBeNullOrEmpty
{
    [CmdletBinding()]
    [OutputType([System.String])]
    param
    (
        [Parameter(Mandatory = $true)]
        [System.Management.Automation.Language.CommandAst]
        $CommandAst,

        [Parameter(Mandatory = $true, ParameterSetName = 'Pester6')]
        [System.Management.Automation.SwitchParameter]
        $Pester6,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $UseNamedParameters,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $UsePositionalParameters
    )

    $assertBoundParameterParameters = @{
        BoundParameterList     = $PSBoundParameters
        MutuallyExclusiveList1 = @('UseNamedParameters')
        MutuallyExclusiveList2 = @('UsePositionalParameters')
    }

    Assert-BoundParameter @assertBoundParameterParameters

    Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ParsingCommandAst -f $CommandAst.Extent.Text)

    # Determine if the command is negated
    $isNegated = Test-PesterCommandNegated -CommandAst $CommandAst

    $sourceSyntaxVersion = Get-PesterCommandSyntaxVersion -CommandAst $CommandAst

    # Parse the command elements and convert them to Pester 6 syntax
    if ($PSCmdlet.ParameterSetName -eq 'Pester6')
    {
        Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ConvertingFromTo -f $sourceSyntaxVersion, '6')

        # Add the correct Pester command based on negation
        $newExtentText = $isNegated ? 'Should-BeTruthy' : 'Should-BeFalsy'

        $getPesterCommandParameterParameters = @{
            CommandAst          = $CommandAst
            CommandName         = 'Should'
            IgnoreParameter     = 'BeNullOrEmpty', 'Not'
            PositionalParameter = 'Because', 'ActualValue'
        }

        $commandParameters = Get-PesterCommandParameter @getPesterCommandParameterParameters

        # Determine if named or positional parameters should be forcibly used
        if ($UseNamedParameters.IsPresent)
        {
            $commandParameters.Keys.ForEach({ $commandParameters.$_.Positional = $false })
        }
        elseif ($UsePositionalParameters.IsPresent)
        {
            # First set all to named parameters
            $commandParameters.Keys.ForEach({ $commandParameters.$_.Positional = $false })

            <#
                If a previous positional parameter is missing then the ones behind
                it cannot be set to positional.
            #>

            if ($commandParameters.ActualValue)
            {
                $commandParameters.ActualValue.Positional = $true

                if ($commandParameters.Because)
                {
                    $commandParameters.Because.Positional = $true
                }
            }
        }

        $newExtentText += $commandParameters.ActualValue.Positional ? (' {0}' -f $commandParameters.ActualValue.ExtentText) : ''

        if ($commandParameters.Because -and $commandParameters.Because.Positional)
        {
            # Only add second positional if the first positional was present.
            if ($commandParameters.ActualValue.Positional)
            {
                $newExtentText += ' {0}' -f $commandParameters.Because.ExtentText
            }
            else
            {
                # First positional parameter was not present, so set the second to named parameter.
                $commandParameters.Because.Positional = $false
            }
        }

        # Holds the new parameter names so they can be added in alphabetical order.
        $parameterNames = @()

        foreach ($currentParameter in $commandParameters.Keys)
        {
            if ($commandParameters.$currentParameter.Positional -eq $true)
            {
                continue
            }

            switch ($currentParameter)
            {
                'ActualValue'
                {
                    $parameterNames += @{
                        Actual = 'ActualValue'
                    }

                    break
                }

                default
                {
                    $parameterNames += @{
                        $currentParameter = $currentParameter
                    }

                    break
                }
            }
        }

        # This handles the named parameters in the command elements, added in alphabetical order.
        foreach ($currentParameter in $parameterNames.Keys | Sort-Object)
        {
            $originalParameterName = $parameterNames.$currentParameter

            $newExtentText += ' -{0} {1}' -f $currentParameter, $commandParameters.$originalParameterName.ExtentText
        }
    }

    Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ConvertedCommand -f $CommandAst.Extent.Text, $newExtentText)

    return $newExtentText
}
#EndRegion '.\Private\Convert-ShouldBeNullOrEmpty.ps1' 195
#Region '.\Private\Convert-ShouldBeOfType.ps1' -1

<#
    .SYNOPSIS
        Converts a command `Should -BeOfType` to the specified Pester syntax.
 
    .DESCRIPTION
        The Convert-ShouldBe function is used to convert a command `Should -BeOfType`
        to the specified Pester syntax.
 
    .PARAMETER CommandAst
        The CommandAst object representing the command to be converted.
 
    .PARAMETER Pester6
        Specifies that the command should be converted to Pester version 6 syntax.
 
    .PARAMETER UseNamedParameters
        Specifies whether to use named parameters in the converted syntax.
 
    .PARAMETER UsePositionalParameters
        Specifies whether to use positional parameters in the converted syntax,
        where supported.
 
    .EXAMPLE
        $commandAst = [System.Management.Automation.Language.Parser]::ParseInput('Should -BeOfType [System.String]')
        Convert-ShouldBeOfType -CommandAst $commandAst -Pester6
 
        This example converts the `Should -BeOfType [System.String]` command to Pester 6 syntax.
 
    .NOTES
        Pester 5 Syntax:
            Should -BeOfType [[-ActualValue] <Object>] [[-ExpectedType] <Object>] [[-Because] <string>] [-Not]
 
            Positional parameters:
                Position 1: ExpectedType
                Position 2: Because
 
        Pester 6 Syntax:
            Should-HaveType [[-Actual] <Object>] [-Expected] <Type> [-Because <String>]
            Should-NotHaveType [[-Actual] <Object>] [-Expected] <Object> [-Because <String>]
 
            Positional parameters:
                Position 1: Expected
                Position 2: Actual
 
        Conversion notes:
            The expected value should be surrounded by parenthesis after conversion
            in v6, e.g. `[System.String]` -> `([System.String])`.
 
            The `-ActualValue` parameter is only supported as a named parameter in
            v5 even if syntax says otherwise. If ActualValue is used it will concatenate
            with the Because value and wrongly always return an array. Did not find
            a way to prevent that.
 
            The `-Not` parameter is not supported in v6. It should be changed to the
            command `Should-NotHaveType`.
 
            The `-Because` parameter is only supported as a named parameter in v6.
#>

function Convert-ShouldBeOfType
{
    [CmdletBinding()]
    [OutputType([System.String])]
    param
    (
        [Parameter(Mandatory = $true)]
        [System.Management.Automation.Language.CommandAst]
        $CommandAst,

        [Parameter(Mandatory = $true, ParameterSetName = 'Pester6')]
        [System.Management.Automation.SwitchParameter]
        $Pester6,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $UseNamedParameters,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $UsePositionalParameters
    )

    $assertBoundParameterParameters = @{
        BoundParameterList     = $PSBoundParameters
        MutuallyExclusiveList1 = @('UseNamedParameters')
        MutuallyExclusiveList2 = @('UsePositionalParameters')
    }

    Assert-BoundParameter @assertBoundParameterParameters

    Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ParsingCommandAst -f $CommandAst.Extent.Text)

    # Determine if the command is negated
    $isNegated = Test-PesterCommandNegated -CommandAst $CommandAst

    $sourceSyntaxVersion = Get-PesterCommandSyntaxVersion -CommandAst $CommandAst

    # Parse the command elements and convert them to Pester 6 syntax
    if ($PSCmdlet.ParameterSetName -eq 'Pester6')
    {
        Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ConvertingFromTo -f $sourceSyntaxVersion, '6')

        # Add the correct Pester command based on negation
        $newExtentText = $isNegated ? 'Should-NotHaveType' : 'Should-HaveType'

        $getPesterCommandParameterParameters = @{
            CommandAst          = $CommandAst
            CommandName         = 'Should'
            IgnoreParameter     = @(
                'BeOfType'
                'HaveType'
                'Not'
            )
            PositionalParameter = @(
                'ExpectedType'
                'Because'
            )
            NamedParameter      = @(
                'ActualValue'
            )
        }

        $commandParameters = Get-PesterCommandParameter @getPesterCommandParameterParameters

        # Parameter 'Because' is only supported as named parameter in Pester 6 syntax.
        if ($commandParameters.Because)
        {
            $commandParameters.Because.Positional = $false
        }

        # Determine if named or positional parameters should be forcibly used
        if ($UseNamedParameters.IsPresent)
        {
            $commandParameters.Keys.ForEach({ $commandParameters.$_.Positional = $false })
        }
        elseif ($UsePositionalParameters.IsPresent)
        {
            # First set all to named parameters
            $commandParameters.Keys.ForEach({ $commandParameters.$_.Positional = $false })

            <#
                If a previous positional parameter is missing then the ones behind
                it cannot be set to positional.
            #>

            if ($commandParameters.ExpectedType)
            {
                $commandParameters.ExpectedType.Positional = $true

                if ($commandParameters.ActualValue)
                {
                    $commandParameters.ActualValue.Positional = $true
                }
            }
        }

        # '[System.String]' -match '^\[.+\]$'
        if ($commandParameters.ExpectedType.Positional)
        {
            # Add the expected value in parenthesis only if the extent text is a type defined in square brackets.
            $extentTextFormat = $commandParameters.ExpectedType.ExtentText -match '^\[.+\]$' ? ' ({0})' : ' {0}'
            $newExtentText += $extentTextFormat -f $commandParameters.ExpectedType.ExtentText
        }

        $newExtentText += $commandParameters.ActualValue.Positional ? (' {0}' -f $commandParameters.ActualValue.ExtentText) : ''

        # Holds the new parameter names so they can be added in alphabetical order.
        $parameterNames = @()

        foreach ($currentParameter in $commandParameters.Keys)
        {
            if ($commandParameters.$currentParameter.Positional -eq $true)
            {
                continue
            }

            switch ($currentParameter)
            {
                'ActualValue'
                {
                    $parameterNames += @{
                        Actual = 'ActualValue'
                    }

                    break
                }

                'ExpectedType'
                {
                    $parameterNames += @{
                        Expected = 'ExpectedType'
                    }

                    break
                }

                default
                {
                    $parameterNames += @{
                        $currentParameter = $currentParameter
                    }

                    break
                }
            }
        }

        # This handles the named parameters in the command elements, added in alphabetical order.
        foreach ($currentParameter in $parameterNames.Keys | Sort-Object)
        {
            $originalParameterName = $parameterNames.$currentParameter

            # Add the expected value in parenthesis only if the extent text is a type defined in square brackets.
            $extentTextFormat = $originalParameterName -eq 'ExpectedType' -and $commandParameters.$originalParameterName.ExtentText -match '^\[.+\]$' ? '({1})' : '{1}'

            $newExtentText += " -{0} $extentTextFormat" -f $currentParameter, $commandParameters.$originalParameterName.ExtentText
        }
    }

    Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ConvertedCommand -f $CommandAst.Extent.Text, $newExtentText)

    return $newExtentText
}
#EndRegion '.\Private\Convert-ShouldBeOfType.ps1' 221
#Region '.\Private\Convert-ShouldBeTrue.ps1' -1

<#
    .SYNOPSIS
        Converts a command `Should -BeTrue` to the specified Pester syntax.
 
    .DESCRIPTION
        The Convert-ShouldBeTrue function is used to convert a command `Should -BeTrue` to
        the specified Pester syntax.
 
    .PARAMETER CommandAst
        The CommandAst object representing the command to be converted.
 
    .PARAMETER Pester6
        Specifies that the command should be converted to Pester version 6 syntax.
 
    .PARAMETER UseNamedParameters
        Specifies whether to use named parameters in the converted syntax.
 
    .PARAMETER UsePositionalParameters
        Specifies whether to use positional parameters in the converted syntax,
        where supported.
 
    .EXAMPLE
        $commandAst = [System.Management.Automation.Language.Parser]::ParseInput('Should -BeTrue')
        Convert-ShouldBeTrue -CommandAst $commandAst -Pester6
 
        This example converts the `Should -BeTrue` command to Pester 6 syntax.
 
    .NOTES
        Pester 5 Syntax:
            Should -BeTrue [[-ActualValue] <Object>] [[-Because] <string>] [-Not]
 
            Positional parameters:
                Position 1: Because
                Position 2: ActualValue
 
        Pester 6 Syntax:
            Should-BeTrue [[-Actual] <Object>] [[-Because] <String>]
 
            Positional parameters:
                Position 1: Actual
                Position 2: Because
 
        Conversion notes:
            If the Pester 5 syntax is negated it must be converted to Should-BeFalse.
 
            If the Pester 5 syntax uses positional parameters, the conversion must
            convert position 1 to position 2 and vice versa.
#>

function Convert-ShouldBeTrue
{
    [CmdletBinding()]
    [OutputType([System.String])]
    param
    (
        [Parameter(Mandatory = $true)]
        [System.Management.Automation.Language.CommandAst]
        $CommandAst,

        [Parameter(Mandatory = $true, ParameterSetName = 'Pester6')]
        [System.Management.Automation.SwitchParameter]
        $Pester6,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $UseNamedParameters,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $UsePositionalParameters
    )

    $assertBoundParameterParameters = @{
        BoundParameterList     = $PSBoundParameters
        MutuallyExclusiveList1 = @('UseNamedParameters')
        MutuallyExclusiveList2 = @('UsePositionalParameters')
    }

    Assert-BoundParameter @assertBoundParameterParameters

    Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ParsingCommandAst -f $CommandAst.Extent.Text)

    # Determine if the command is negated
    $isNegated = Test-PesterCommandNegated -CommandAst $CommandAst

    $sourceSyntaxVersion = Get-PesterCommandSyntaxVersion -CommandAst $CommandAst

    # Parse the command elements and convert them to Pester 6 syntax
    if ($PSCmdlet.ParameterSetName -eq 'Pester6')
    {
        Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ConvertingFromTo -f $sourceSyntaxVersion, '6')

        # Add the correct Pester command based on negation
        $newExtentText = $isNegated ? 'Should-BeFalse' : 'Should-BeTrue'

        $getPesterCommandParameterParameters = @{
            CommandAst          = $CommandAst
            CommandName         = 'Should'
            IgnoreParameter     = 'BeTrue', 'Not'
            PositionalParameter = 'Because', 'ActualValue'
        }

        $commandParameters = Get-PesterCommandParameter @getPesterCommandParameterParameters

        # Determine if named or positional parameters should be forcibly used
        if ($UseNamedParameters.IsPresent)
        {
            $commandParameters.Keys.ForEach({ $commandParameters.$_.Positional = $false })
        }
        elseif ($UsePositionalParameters.IsPresent)
        {
            # First set all to named parameters
            $commandParameters.Keys.ForEach({ $commandParameters.$_.Positional = $false })

            <#
                If a previous positional parameter is missing then the ones behind
                it cannot be set to positional.
            #>

            if ($commandParameters.Because)
            {
                $commandParameters.Because.Positional = $true

                if ($commandParameters.ActualValue)
                {
                    $commandParameters.ActualValue.Positional = $true
                }
            }
        }

        $newExtentText += $commandParameters.ActualValue.Positional ? (' {0}' -f $commandParameters.ActualValue.ExtentText) : ''

        if ($commandParameters.Because -and $commandParameters.Because.Positional)
        {
            # Only add second positional if the first positional was present.
            if ($commandParameters.ActualValue.Positional)
            {
                $newExtentText += ' {0}' -f $commandParameters.Because.ExtentText
            }
            else
            {
                # First positional parameter was not present, so set the second to named parameter.
                $commandParameters.Because.Positional = $false
            }
        }

        # Holds the new parameter names so they can be added in alphabetical order.
        $parameterNames = @()

        foreach ($currentParameter in $commandParameters.Keys)
        {
            if ($commandParameters.$currentParameter.Positional -eq $true)
            {
                continue
            }

            switch ($currentParameter)
            {
                'ActualValue'
                {
                    $parameterNames += @{
                        Actual = 'ActualValue'
                    }

                    break
                }

                default
                {
                    $parameterNames += @{
                        $currentParameter = $currentParameter
                    }

                    break
                }
            }
        }

        # This handles the named parameters in the command elements, added in alphabetical order.
        foreach ($currentParameter in $parameterNames.Keys | Sort-Object)
        {
            $originalParameterName = $parameterNames.$currentParameter

            $newExtentText += ' -{0} {1}' -f $currentParameter, $commandParameters.$originalParameterName.ExtentText
        }
    }

    Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ConvertedCommand -f $CommandAst.Extent.Text, $newExtentText)

    return $newExtentText
}
#EndRegion '.\Private\Convert-ShouldBeTrue.ps1' 190
#Region '.\Private\Convert-ShouldContain.ps1' -1

<#
    .SYNOPSIS
        Converts a command `Should -Contain` to the specified Pester syntax.
 
    .DESCRIPTION
        The Convert-ShouldContain function is used to convert a command `Should -Contain` to
        the specified Pester syntax.
 
    .PARAMETER CommandAst
        The CommandAst object representing the command to be converted.
 
    .PARAMETER Pester6
        Specifies that the command should be converted to Pester version 6 syntax.
 
    .PARAMETER UseNamedParameters
        Specifies whether to use named parameters in the converted syntax.
 
    .PARAMETER UsePositionalParameters
        Specifies whether to use positional parameters in the converted syntax,
        where supported.
 
    .EXAMPLE
        $commandAst = [System.Management.Automation.Language.Parser]::ParseInput('Should -Contain "Test"')
        Convert-ShouldContain -CommandAst $commandAst -Pester6
 
        This example converts the `Should -Contain "Test"` command to Pester 6 syntax.
 
    .NOTES
        Pester 5 Syntax:
            Should -Contain [[-ActualValue] <Object>] [[-ExpectedValue] <Object>] [[-Because] <string>] [-Not]
 
            Positional parameters:
                Position 1: ExpectedValue
                Position 2: Because
 
        Pester 6 Syntax:
            Should-ContainCollection [-Actual] <Object>] [-Expected] <Object> [-Because <String>]
            Should-NotContainCollection [[-Actual] <Object>] [-Expected] <Object> [-Because <String>]
 
            Positional parameters:
                Position 1: Expected
                Position 2: Actual
#>

function Convert-ShouldContain
{
    [CmdletBinding()]
    [OutputType([System.String])]
    param
    (
        [Parameter(Mandatory = $true)]
        [System.Management.Automation.Language.CommandAst]
        $CommandAst,

        [Parameter(Mandatory = $true, ParameterSetName = 'Pester6')]
        [System.Management.Automation.SwitchParameter]
        $Pester6,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $UseNamedParameters,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $UsePositionalParameters
    )

    $assertBoundParameterParameters = @{
        BoundParameterList     = $PSBoundParameters
        MutuallyExclusiveList1 = @('UseNamedParameters')
        MutuallyExclusiveList2 = @('UsePositionalParameters')
    }

    Assert-BoundParameter @assertBoundParameterParameters

    Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ParsingCommandAst -f $CommandAst.Extent.Text)

    # Determine if the command is negated
    $isNegated = Test-PesterCommandNegated -CommandAst $CommandAst

    $sourceSyntaxVersion = Get-PesterCommandSyntaxVersion -CommandAst $CommandAst

    # Parse the command elements and convert them to Pester 6 syntax
    if ($PSCmdlet.ParameterSetName -eq 'Pester6')
    {
        Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ConvertingFromTo -f $sourceSyntaxVersion, '6')

        # Add the correct Pester command based on negation
        $newExtentText = $isNegated ? 'Should-NotContainCollection' : 'Should-ContainCollection'

        $getPesterCommandParameterParameters = @{
            CommandAst          = $CommandAst
            CommandName         = 'Should'
            IgnoreParameter     = @(
                'Contain'
                'Not'
            )
            PositionalParameter = @(
                'ExpectedValue'
                'Because'
            )
            NamedParameter      = @(
                'ActualValue'
            )
        }

        $commandParameters = Get-PesterCommandParameter @getPesterCommandParameterParameters

        # Parameter 'Because' is only supported as named parameter in Pester 6 syntax.
        if ($commandParameters.Because)
        {
            $commandParameters.Because.Positional = $false
        }

        # Determine if named or positional parameters should be forcibly used
        if ($UseNamedParameters.IsPresent)
        {
            $commandParameters.Keys.ForEach({ $commandParameters.$_.Positional = $false })
        }
        elseif ($UsePositionalParameters.IsPresent)
        {
            # First set all to named parameters
            $commandParameters.Keys.ForEach({ $commandParameters.$_.Positional = $false })

            <#
                If a previous positional parameter is missing then the ones behind
                it cannot be set to positional.
            #>

            if ($commandParameters.ExpectedValue)
            {
                $commandParameters.ExpectedValue.Positional = $true

                if ($commandParameters.ActualValue)
                {
                    $commandParameters.ActualValue.Positional = $true
                }
            }
        }

        $newExtentText += $commandParameters.ExpectedValue.Positional ? (' {0}' -f $commandParameters.ExpectedValue.ExtentText) : ''
        $newExtentText += $commandParameters.ActualValue.Positional ? (' {0}' -f $commandParameters.ActualValue.ExtentText) : ''

        # Holds the new parameter names so they can be added in alphabetical order.
        $parameterNames = @()

        foreach ($currentParameter in $commandParameters.Keys)
        {
            if ($commandParameters.$currentParameter.Positional -eq $true)
            {
                continue
            }

            switch ($currentParameter)
            {
                'ActualValue'
                {
                    $parameterNames += @{
                        Actual = 'ActualValue'
                    }

                    break
                }

                'ExpectedValue'
                {
                    $parameterNames += @{
                        Expected = 'ExpectedValue'
                    }

                    break
                }

                default
                {
                    $parameterNames += @{
                        $currentParameter = $currentParameter
                    }

                    break
                }
            }
        }

        # This handles the named parameters in the command elements, added in alphabetical order.
        foreach ($currentParameter in $parameterNames.Keys | Sort-Object)
        {
            $originalParameterName = $parameterNames.$currentParameter

            $newExtentText += ' -{0} {1}' -f $currentParameter, $commandParameters.$originalParameterName.ExtentText
        }
    }

    Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ConvertedCommand -f $CommandAst.Extent.Text, $newExtentText)

    return $newExtentText
}
#EndRegion '.\Private\Convert-ShouldContain.ps1' 196
#Region '.\Private\Convert-ShouldMatch.ps1' -1

<#
    .SYNOPSIS
        Converts a command `Should -Match` to the specified Pester syntax.
 
    .DESCRIPTION
        The Convert-ShouldMatch function is used to convert a command `Should -Match` to
        the specified Pester syntax.
 
    .PARAMETER CommandAst
        The CommandAst object representing the command to be converted.
 
    .PARAMETER Pester6
        Specifies that the command should be converted to Pester version 6 syntax.
 
    .PARAMETER UseNamedParameters
        Specifies whether to use named parameters in the converted syntax.
 
    .PARAMETER UsePositionalParameters
        Specifies whether to use positional parameters in the converted syntax,
        where supported.
 
    .EXAMPLE
        $commandAst = [System.Management.Automation.Language.Parser]::ParseInput('Should -Match "Test"')
        Convert-ShouldMatch -CommandAst $commandAst -Pester6
 
        This example converts the `Should -Match "Test"` command to Pester 6 syntax.
 
    .NOTES
        Pester 5 Syntax:
            Should -Match [[-ActualValue] <Object>] [[-RegularExpression] <Object>] [[-Because] <string>] [-Not]
 
            Positional parameters:
                Position 1: ExpectedValue
                Position 2: Because
                Position 3: ActualValue
 
        Pester 6 Syntax:
            # TODO: Update the Pester 6 syntax once it is finalized.
            Should-MatchString [[-Actual] <Object>] [-Expected] <Object> [-Because <String>]
            Should-NotMatchString [[-Actual] <Object>] [-Expected] <Object> [-Because <String>]
 
            Positional parameters:
                Position 1: Expected
                Position 2: Actual
#>

function Convert-ShouldMatch
{
    [CmdletBinding()]
    [OutputType([System.String])]
    param
    (
        [Parameter(Mandatory = $true)]
        [System.Management.Automation.Language.CommandAst]
        $CommandAst,

        [Parameter(Mandatory = $true, ParameterSetName = 'Pester6')]
        [System.Management.Automation.SwitchParameter]
        $Pester6,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $UseNamedParameters,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $UsePositionalParameters
    )

    $assertBoundParameterParameters = @{
        BoundParameterList     = $PSBoundParameters
        MutuallyExclusiveList1 = @('UseNamedParameters')
        MutuallyExclusiveList2 = @('UsePositionalParameters')
    }

    Assert-BoundParameter @assertBoundParameterParameters

    Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ParsingCommandAst -f $CommandAst.Extent.Text)

    # Determine if the command is negated
    $isNegated = Test-PesterCommandNegated -CommandAst $CommandAst

    $sourceSyntaxVersion = Get-PesterCommandSyntaxVersion -CommandAst $CommandAst

    # Parse the command elements and convert them to Pester 6 syntax
    if ($PSCmdlet.ParameterSetName -eq 'Pester6')
    {
        Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ConvertingFromTo -f $sourceSyntaxVersion, '6')

        # Add the correct Pester command based on negation
        $newExtentText = $isNegated ? 'Should-NotMatchString' : 'Should-MatchString'

        $getPesterCommandParameterParameters = @{
            CommandAst          = $CommandAst
            CommandName         = 'Should'
            IgnoreParameter     = @(
                'Match'
                'Not'
            )
            PositionalParameter = @(
                'RegularExpression'
                'Because'
                'ActualValue'
            )
        }

        $commandParameters = Get-PesterCommandParameter @getPesterCommandParameterParameters

        # Parameter 'Because' is only supported as named parameter in Pester 6 syntax.
        if ($commandParameters.Because)
        {
            $commandParameters.Because.Positional = $false
        }

        # Determine if named or positional parameters should be forcibly used
        if ($UseNamedParameters.IsPresent)
        {
            $commandParameters.Keys.ForEach({ $commandParameters.$_.Positional = $false })
        }
        elseif ($UsePositionalParameters.IsPresent)
        {
            # First set all to named parameters
            $commandParameters.Keys.ForEach({ $commandParameters.$_.Positional = $false })

            <#
                If a previous positional parameter is missing then the ones behind
                it cannot be set to positional.
            #>

            if ($commandParameters.RegularExpression)
            {
                $commandParameters.RegularExpression.Positional = $true

                if ($commandParameters.ActualValue)
                {
                    $commandParameters.ActualValue.Positional = $true
                }
            }
        }

        $newExtentText += $commandParameters.RegularExpression.Positional ? (' {0}' -f $commandParameters.RegularExpression.ExtentText) : ''
        $newExtentText += $commandParameters.ActualValue.Positional ? (' {0}' -f $commandParameters.ActualValue.ExtentText) : ''

        # Holds the new parameter names so they can be added in alphabetical order.
        $parameterNames = @()

        foreach ($currentParameter in $commandParameters.Keys)
        {
            if ($commandParameters.$currentParameter.Positional -eq $true)
            {
                continue
            }

            switch ($currentParameter)
            {
                'ActualValue'
                {
                    $parameterNames += @{
                        Actual = 'ActualValue'
                    }

                    break
                }

                'RegularExpression'
                {
                    $parameterNames += @{
                        Expected = 'RegularExpression'
                    }

                    break
                }

                default
                {
                    $parameterNames += @{
                        $currentParameter = $currentParameter
                    }

                    break
                }
            }
        }

        # This handles the named parameters in the command elements, added in alphabetical order.
        foreach ($currentParameter in $parameterNames.Keys | Sort-Object)
        {
            $originalParameterName = $parameterNames.$currentParameter

            $newExtentText += ' -{0} {1}' -f $currentParameter, $commandParameters.$originalParameterName.ExtentText
        }
    }

    Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ConvertedCommand -f $CommandAst.Extent.Text, $newExtentText)

    return $newExtentText
}
#EndRegion '.\Private\Convert-ShouldMatch.ps1' 196
#Region '.\Private\Convert-ShouldMatchExactly.ps1' -1

<#
    .SYNOPSIS
        Converts a command `Should -MatchExactly` to the specified Pester syntax.
 
    .DESCRIPTION
        The Convert-ShouldBe function is used to convert a command `Should -MatchExactly` to
        the specified Pester syntax.
 
    .PARAMETER CommandAst
        The CommandAst object representing the command to be converted.
 
    .PARAMETER Pester6
        Specifies that the command should be converted to Pester version 6 syntax.
 
    .PARAMETER UseNamedParameters
        Specifies whether to use named parameters in the converted syntax.
 
    .PARAMETER UsePositionalParameters
        Specifies whether to use positional parameters in the converted syntax,
        where supported.
 
    .EXAMPLE
        $commandAst = [System.Management.Automation.Language.Parser]::ParseInput('Should -MatchExactly "Test"')
        Convert-ShouldMatchExactly -CommandAst $commandAst -Pester6
 
        This example converts the `Should -MatchExactly "Test"` command to Pester 6 syntax.
 
    .NOTES
        Pester 5 Syntax:
            Should -MatchExactly [[-ActualValue] <Object>] [-Not] [[-ExpectedValue] <Object>] [-Because <Object>]
 
            Positional parameters:
                Position 1: ExpectedValue
                Position 2: Because
                Position 3: ActualValue
 
        Pester 6 Syntax:
            Should-BeString [[-Actual] <Object>] [[-Expected] <String>] [-Because <String>] [-CaseSensitive] [-IgnoreWhitespace]
            Should-NotBeString [[-Actual] <Object>] [[-Expected] <String>] [-Because <String>] [-CaseSensitive] [-IgnoreWhitespace]
 
            Positional parameters:
                Position 1: Expected
                Position 2: Actual
#>

function Convert-ShouldMatchExactly
{
    [CmdletBinding()]
    [OutputType([System.String])]
    param
    (
        [Parameter(Mandatory = $true)]
        [System.Management.Automation.Language.CommandAst]
        $CommandAst,

        [Parameter(Mandatory = $true, ParameterSetName = 'Pester6')]
        [System.Management.Automation.SwitchParameter]
        $Pester6,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $UseNamedParameters,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $UsePositionalParameters
    )

    $assertBoundParameterParameters = @{
        BoundParameterList     = $PSBoundParameters
        MutuallyExclusiveList1 = @('UseNamedParameters')
        MutuallyExclusiveList2 = @('UsePositionalParameters')
    }

    Assert-BoundParameter @assertBoundParameterParameters

    Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ParsingCommandAst -f $CommandAst.Extent.Text)

    # Determine if the command is negated
    $isNegated = Test-PesterCommandNegated -CommandAst $CommandAst

    $sourceSyntaxVersion = Get-PesterCommandSyntaxVersion -CommandAst $CommandAst

    # Parse the command elements and convert them to Pester 6 syntax
    if ($PSCmdlet.ParameterSetName -eq 'Pester6')
    {
        Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ConvertingFromTo -f $sourceSyntaxVersion, '6')

        # Add the correct Pester command based on negation
        $newExtentText = $isNegated ? 'Should-NotMatchString' : 'Should-MatchString'

        # Always add the `-CaseSensitive` parameter since MatchExactly was case-sensitive.
        $newExtentText += ' -CaseSensitive'

        $getPesterCommandParameterParameters = @{
            CommandAst          = $CommandAst
            CommandName         = 'Should'
            IgnoreParameter     = @(
                'CMATCH'
                'MatchExactly'
                'Not'
            )
            PositionalParameter = @(
                'RegularExpression'
                'Because'
                'ActualValue'
            )
        }

        $commandParameters = Get-PesterCommandParameter @getPesterCommandParameterParameters

        # Parameter 'Because' is only supported as named parameter in Pester 6 syntax.
        if ($commandParameters.Because)
        {
            $commandParameters.Because.Positional = $false
        }

        # Determine if named or positional parameters should be forcibly used
        if ($UseNamedParameters.IsPresent)
        {
            $commandParameters.Keys.ForEach({ $commandParameters.$_.Positional = $false })
        }
        elseif ($UsePositionalParameters.IsPresent)
        {
            # First set all to named parameters
            $commandParameters.Keys.ForEach({ $commandParameters.$_.Positional = $false })

            <#
                If a previous positional parameter is missing then the ones behind
                it cannot be set to positional.
            #>

            if ($commandParameters.RegularExpression)
            {
                $commandParameters.RegularExpression.Positional = $true

                if ($commandParameters.ActualValue)
                {
                    $commandParameters.ActualValue.Positional = $true
                }
            }
        }

        $newExtentText += $commandParameters.RegularExpression.Positional ? (' {0}' -f $commandParameters.RegularExpression.ExtentText) : ''
        $newExtentText += $commandParameters.ActualValue.Positional ? (' {0}' -f $commandParameters.ActualValue.ExtentText) : ''

        # Holds the new parameter names so they can be added in alphabetical order.
        $parameterNames = @()

        foreach ($currentParameter in $commandParameters.Keys)
        {
            if ($commandParameters.$currentParameter.Positional -eq $true)
            {
                continue
            }

            switch ($currentParameter)
            {
                'ActualValue'
                {
                    $parameterNames += @{
                        Actual = 'ActualValue'
                    }

                    break
                }

                'RegularExpression'
                {
                    $parameterNames += @{
                        Expected = 'RegularExpression'
                    }

                    break
                }

                default
                {
                    $parameterNames += @{
                        $currentParameter = $currentParameter
                    }

                    break
                }
            }
        }

        # This handles the named parameters in the command elements, added in alphabetical order.
        foreach ($currentParameter in $parameterNames.Keys | Sort-Object)
        {
            $originalParameterName = $parameterNames.$currentParameter

            $newExtentText += ' -{0} {1}' -f $currentParameter, $commandParameters.$originalParameterName.ExtentText
        }
    }

    Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ConvertedCommand -f $CommandAst.Extent.Text, $newExtentText)

    return $newExtentText
}
#EndRegion '.\Private\Convert-ShouldMatchExactly.ps1' 199
#Region '.\Private\Convert-ShouldNotThrow.ps1' -1

<#
    .SYNOPSIS
        Converts a command `Should -Not -Throw` to the specified Pester syntax.
 
    .DESCRIPTION
        The Convert-ShouldBe function is used to convert a command `Should -Not -Throw` to
        the specified Pester syntax.
 
    .PARAMETER CommandAst
        The CommandAst object representing the command to be converted.
 
    .PARAMETER Pester6
        Specifies that the command should be converted to Pester version 6 syntax.
 
    .PARAMETER UseNamedParameters
        Specifies whether to use named parameters in the converted syntax.
 
    .PARAMETER UsePositionalParameters
        Specifies whether to use positional parameters in the converted syntax,
        where supported.
 
    .EXAMPLE
        $commandAst = [System.Management.Automation.Language.Parser]::ParseInput('Should -Not -Throw')
        Convert-ShouldThrow -CommandAst $commandAst -Pester6
 
        This example converts the `Should -Not -Throw` command to Pester 6 syntax.
 
    .NOTES
        Pester 5 Syntax:
            Should -Throw [[-ActualValue] <Object>] [[-ExpectedMessage] <string>] [[-ErrorId] <string>] [[-ExceptionType] <type>] [[-Because] <string>] [-Not] [-PassThru]
 
            Positional parameters:
                Position 1: ExceptionMessage
                Position 2: ErrorId
                Position 3: ExceptionType
                Position 4: Because
 
        Pester 6 Syntax:
            There are no Should-* command to call in v6. In v6 the scriptblock
            should be called either directly or using the call operator, e.g:
 
            $null = & (<ActualValue>)
 
        Conversion notes:
            From Frode: "$null = & (<actualvalue>) should work for variables,
            script blocks and expressions (note parentheses). Running the code
            directly will send data to StandardOutput in the Test-object. Not a
            big deal unless there's a lot of output, but might as well assign it
            to null like -Throw."
#>

function Convert-ShouldNotThrow
{
    [CmdletBinding()]
    [OutputType([System.String])]
    param
    (
        [Parameter(Mandatory = $true)]
        [System.Management.Automation.Language.CommandAst]
        $CommandAst,

        [Parameter(Mandatory = $true, ParameterSetName = 'Pester6')]
        [System.Management.Automation.SwitchParameter]
        $Pester6,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $UseNamedParameters,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $UsePositionalParameters
    )

    $assertBoundParameterParameters = @{
        BoundParameterList     = $PSBoundParameters
        MutuallyExclusiveList1 = @('UseNamedParameters')
        MutuallyExclusiveList2 = @('UsePositionalParameters')
    }

    Assert-BoundParameter @assertBoundParameterParameters

    Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ParsingCommandAst -f $CommandAst.Extent.Text)

    # Determine if the command is negated
    $isNegated = Test-PesterCommandNegated -CommandAst $CommandAst

    $sourceSyntaxVersion = Get-PesterCommandSyntaxVersion -CommandAst $CommandAst

    # Parse the command elements and convert them to Pester 6 syntax
    if ($PSCmdlet.ParameterSetName -eq 'Pester6')
    {
        Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ConvertingFromTo -f $sourceSyntaxVersion, '6')

        if ($isNegated)
        {
            <#
                Must extract the scriptblock from the CommandAst extent, the scriptblock
                is passed as the parameter ActualValue or passed thru the pipeline.
            #>

            $newExtentText = '$null = & ({0})' -f (Get-PipelineBeforeShould -CommandAst $CommandAst -ParameterName 'ActualValue' -ParsePipeline)
        }
        else
        {
            #$shouldNotThrowNotImplementedMessage = $script:localizedData.ShouldNotThrow_NotImplemented

            $PSCmdlet.ThrowTerminatingError(
                [System.Management.Automation.ErrorRecord]::new(
                    'Convert-ShouldNotThrow should not be called without a negation parameter. Call Convert-ShouldThrow instead.', #$shouldNotThrowNotImplementedMessage,
                    'CSNT0001', # cspell: disable-line
                    [System.Management.Automation.ErrorCategory]::NotImplemented,
                    $CommandAst.Extent.Text
                )
            )
        }
    }

    Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ConvertedCommand -f $CommandAst.Extent.Text, $newExtentText)

    return $newExtentText
}
#EndRegion '.\Private\Convert-ShouldNotThrow.ps1' 121
#Region '.\Private\Convert-ShouldThrow.ps1' -1

<#
    .SYNOPSIS
        Converts a command `Should -Throw` to the specified Pester syntax.
 
    .DESCRIPTION
        The Convert-ShouldBe function is used to convert a command `Should -Throw` to
        the specified Pester syntax.
 
    .PARAMETER CommandAst
        The CommandAst object representing the command to be converted.
 
    .PARAMETER Pester6
        Specifies that the command should be converted to Pester version 6 syntax.
 
    .PARAMETER UseNamedParameters
        Specifies whether to use named parameters in the converted syntax.
 
    .PARAMETER UsePositionalParameters
        Specifies whether to use positional parameters in the converted syntax,
        where supported.
 
    .EXAMPLE
        $commandAst = [System.Management.Automation.Language.Parser]::ParseInput('Should -Throw "Test"')
        Convert-ShouldThrow -CommandAst $commandAst -Pester6
 
        This example converts the `Should -Throw "Test"` command to Pester 6 syntax.
 
    .NOTES
        Pester 5 Syntax:
            Should -Throw [[-ActualValue] <Object>] [[-ExpectedMessage] <string>] [[-ErrorId] <string>] [[-ExceptionType] <type>] [[-Because] <string>] [-Not] [-PassThru]
 
            Positional parameters:
                Position 1: ExpectedMessage
                Position 2: ErrorId
                Position 3: ExceptionType
                Position 4: Because
 
        Pester 6 Syntax:
            Should-Throw [-ScriptBlock] <ScriptBlock> [[-ExceptionType] <Type>] [[-ExceptionMessage] <String>] [[-FullyQualifiedErrorId] <String>] [-AllowNonTerminatingError] [[-Because] <String>]
 
            Positional parameters:
                Position 1: ExceptionMessage
                Position 2: FullyQualifiedErrorId
                Position 3: ExceptionType
                Position 4: Because
 
        Conversion notes:
            PassThru is the default in Pester 6, so it can be ignored in the conversion.
            But must be handled if it can have negative impact were it was not used
            before.
 
            TODO: Verify the positional parameters in next v6 alpha, and that they
                  are only the four. The code below assume they will be the same
                  as v5 in a future v6 alpha.
#>

function Convert-ShouldThrow
{
    [CmdletBinding()]
    [OutputType([System.String])]
    param
    (
        [Parameter(Mandatory = $true)]
        [System.Management.Automation.Language.CommandAst]
        $CommandAst,

        [Parameter(Mandatory = $true, ParameterSetName = 'Pester6')]
        [System.Management.Automation.SwitchParameter]
        $Pester6,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $UseNamedParameters,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $UsePositionalParameters
    )

    $assertBoundParameterParameters = @{
        BoundParameterList     = $PSBoundParameters
        MutuallyExclusiveList1 = @('UseNamedParameters')
        MutuallyExclusiveList2 = @('UsePositionalParameters')
    }

    Assert-BoundParameter @assertBoundParameterParameters

    Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ParsingCommandAst -f $CommandAst.Extent.Text)

    # Determine if the command is negated
    $isNegated = Test-PesterCommandNegated -CommandAst $CommandAst

    $sourceSyntaxVersion = Get-PesterCommandSyntaxVersion -CommandAst $CommandAst

    # Parse the command elements and convert them to Pester 6 syntax
    if ($PSCmdlet.ParameterSetName -eq 'Pester6')
    {
        Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ConvertingFromTo -f $sourceSyntaxVersion, '6')

        # Add the correct Pester command based on negation
        if ($isNegated)
        {
            #$shouldThrowNotImplementedMessage = $script:localizedData.ShouldThrow_NotImplemented

            $PSCmdlet.ThrowTerminatingError(
                [System.Management.Automation.ErrorRecord]::new(
                    'Convert-ShouldThrow should not be called with a negation parameter. Call Convert-ShouldNotThrow instead.', #$shouldThrowNotImplementedMessage,
                    'CST0001', # cspell: disable-line
                    [System.Management.Automation.ErrorCategory]::NotImplemented,
                    $CommandAst.Extent.Text
                )
            )
        }
        else
        {
            $newExtentText = 'Should-Throw'
        }

        $getPesterCommandParameterParameters = @{
            CommandAst          = $CommandAst
            CommandName         = 'Should'
            IgnoreParameter     = @(
                'Throw'
                'Not'
                'PassThru'
            )
            PositionalParameter = @(
                'ExpectedMessage'
                'ErrorId'
                'ExceptionType'
                'Because'
            )
            NamedParameter      = @(
                'ActualValue'
            )
        }

        $commandParameters = Get-PesterCommandParameter @getPesterCommandParameterParameters

        # Determine if named or positional parameters should be forcibly used
        if ($UseNamedParameters.IsPresent)
        {
            $commandParameters.Keys.ForEach({ $commandParameters.$_.Positional = $false })
        }
        elseif ($UsePositionalParameters.IsPresent)
        {
            # First set all to named parameters
            $commandParameters.Keys.ForEach({ $commandParameters.$_.Positional = $false })

            <#
                If a previous positional parameter is missing then the ones behind
                it cannot be set to positional.
            #>

            if ($commandParameters.ExpectedMessage)
            {
                $commandParameters.ExpectedMessage.Positional = $true

                if ($commandParameters.ErrorId)
                {
                    $commandParameters.ErrorId.Positional = $true

                    if ($commandParameters.ExceptionType)
                    {
                        $commandParameters.ExceptionType.Positional = $true

                        if ($commandParameters.Because)
                        {
                            $commandParameters.Because.Positional = $true
                        }
                    }
                }
            }
        }

        $newExtentText += $commandParameters.ExpectedMessage.Positional ? (' {0}' -f $commandParameters.ExpectedMessage.ExtentText) : ''
        $newExtentText += $commandParameters.ErrorId.Positional ? (' {0}' -f $commandParameters.ErrorId.ExtentText) : ''
        $newExtentText += $commandParameters.ExceptionType.Positional ? (' {0}' -f $commandParameters.ExceptionType.ExtentText) : ''
        $newExtentText += $commandParameters.Because.Positional ? (' {0}' -f $commandParameters.Because.ExtentText) : ''

        # Holds the new parameter names so they can be added in alphabetical order.
        $parameterNames = @()

        foreach ($currentParameter in $commandParameters.Keys)
        {
            if ($commandParameters.$currentParameter.Positional -eq $true)
            {
                continue
            }

            switch ($currentParameter)
            {
                'ExpectedMessage'
                {
                    $parameterNames += @{
                        ExceptionMessage = 'ExpectedMessage'
                    }

                    break
                }

                'ErrorId'
                {
                    $parameterNames += @{
                        FullyQualifiedErrorId = 'ErrorId'
                    }

                    break
                }

                'ActualValue'
                {
                    $parameterNames += @{
                        ScriptBlock = 'ActualValue'
                    }

                    break
                }

                default
                {
                    $parameterNames += @{
                        $currentParameter = $currentParameter
                    }

                    break
                }
            }
        }

        # This handles the named parameters in the command elements, added in alphabetical order.
        foreach ($currentParameter in $parameterNames.Keys | Sort-Object)
        {
            $originalParameterName = $parameterNames.$currentParameter

            $newExtentText += ' -{0} {1}' -f $currentParameter, $commandParameters.$originalParameterName.ExtentText
        }
    }

    Write-Debug -Message ($script:localizedData.Convert_Should_Debug_ConvertedCommand -f $CommandAst.Extent.Text, $newExtentText)

    return $newExtentText
}
#EndRegion '.\Private\Convert-ShouldThrow.ps1' 242
#Region '.\Private\ConvertTo-ActualParameterName.ps1' -1

<#
    .SYNOPSIS
        Converts a unambiguous abbreviated named parameter to its actual parameter
        name.
 
    .DESCRIPTION
        The ConvertTo-ActualParameterName function returns the actual parameter
        name of a unambiguous abbreviated named parameter.
 
    .PARAMETER CommandName
        Specifies the name of the command. Must be one supported.
 
    .PARAMETER NamedParameter
        Specifies the unambiguous abbreviated named parameter to convert.
 
    .OUTPUTS
        System.String
 
        Holds the converted parameter name.
 
    .EXAMPLE
        ConvertTo-ActualParameterName -CommandName 'Should' -NamedParameter 'Actual'
 
        Returns the correct parameter name `ActualValue`.
#>

function ConvertTo-ActualParameterName
{
    [CmdletBinding()]
    [OutputType([System.String])]
    param
    (
        [Parameter(Mandatory = $true)]
        [ValidateSet('Should')]
        [System.String]
        $CommandName,

        [Parameter(Mandatory = $true)]
        [System.String]
        $NamedParameter
    )

    switch ($CommandName)
    {
        # Should in Pester 5.
        'Should'
        {
            $parameterNames = @(
                # Parameters names.
                'ActualValue'
                'Alias'
                'Be'
                'Because'
                'BeExactly'
                'BeFalse'
                'BeGreaterOrEqual'
                'BeGreaterThan'
                'BeIn'
                'BeLessOrEqual'
                'BeLessThan'
                'BeLike'
                'BeLikeExactly'
                'BeNullOrEmpty'
                'BeOfType'
                'BeTrue'
                'CallerSessionState'
                'CommandName'
                'Contain'
                'Debug'
                'DefaultValue'
                'ErrorAction'
                'ErrorId'
                'ErrorVariable'
                'Exactly'
                'ExceptionType'
                'ExclusiveFilter'
                'Exist'
                'ExpectedContent'
                'ExpectedMessage'
                'ExpectedType'
                'ExpectedValue'
                'FileContentMatch'
                'FileContentMatchExactly'
                'FileContentMatchMultiline'
                'FileContentMatchMultilineExactly'
                'HasArgumentCompleter'
                'HaveCount'
                'HaveParameter'
                'InformationAction'
                'InformationVariable'
                'InParameterSet'
                'Invoke'
                'InvokeVerifiable'
                'Mandatory'
                'Match'
                'MatchExactly'
                'ModuleName'
                'Not'
                'OutBuffer'
                'OutVariable'
                'ParameterFilter'
                'ParameterName'
                'PassThru'
                'PipelineVariable'
                'ProgressAction'
                'RegularExpression'
                'Scope'
                'Throw'
                'Times'
                'Type'
                'Verbose'
                'WarningAction'
                'WarningVariable'

                # Alias parameter names.
                'EQ'
                'CEQ'
                'GT'
                'LE'
                'LT'
                'GE'
                'HaveType'
                'CMATCH'
            )
        }
    }

    # Try to match exact name.
    $result = $parameterNames -match "^$NamedParameter$"

    # Try to match abbreviated name.
    $result = $result ? $result : $parameterNames -match "^$NamedParameter"

    if (-not $result)
    {
        $PSCmdlet.ThrowTerminatingError(
            [System.Management.Automation.ErrorRecord]::new(
                ($script:localizedData.UnknownNamedParameter -f $NamedParameter, $CommandName),
                'CTAPN0002', # cSpell: disable-line
                [System.Management.Automation.ErrorCategory]::InvalidOperation,
                $NamedParameter
            )
        )
    }

    if (${result}?.Count -gt 1)
    {
        $PSCmdlet.ThrowTerminatingError(
            [System.Management.Automation.ErrorRecord]::new(
                ($script:localizedData.AmbiguousNamedParameter -f $NamedParameter, $CommandName),
                'CTAPN0001', # cSpell: disable-line
                [System.Management.Automation.ErrorCategory]::InvalidOperation,
                $NamedParameter
            )
        )
    }

    return $result
}
#EndRegion '.\Private\ConvertTo-ActualParameterName.ps1' 159
#Region '.\Private\Get-AstDefinition.ps1' -1

<#
    .SYNOPSIS
        Retrieves the ScriptBlockAst definition of a PowerShell script file.
 
    .DESCRIPTION
        The Get-AstDefinition function parses a PowerShell script file and retrieves
        the ScriptBlockAst definition. It uses the Parser.ParseFile method from the
        System.Management.Automation.Language namespace to parse the file.
 
    .PARAMETER Path
        Specifies the path to the PowerShell script file(s) to parse.
        This parameter supports pipeline input and accepts both strings and FileInfo
        objects.
 
    .OUTPUTS
        System.Management.Automation.Language.ScriptBlockAst
 
        The ScriptBlockAst definition of the parsed PowerShell script file.
 
    .EXAMPLE
        Get-AstDefinition -Path 'C:\Scripts\Script.ps1'
 
        Retrieves the ScriptBlockAst definition of the 'Script.ps1' file.
 
    .EXAMPLE
        Get-AstDefinition -Path (Get-ChildItem -Path './scripts')
 
        Retrieves the ScriptBlockAst definition of all the files in the path pass
        as pipeline input.
#>

function Get-AstDefinition
{
    [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidMultipleTypeAttributes', '', Justification = 'We want to pass in both strings and FileInfo objects to parameter Path.')]
    [CmdletBinding()]
    [OutputType([System.Management.Automation.Language.ScriptBlockAst])]
    param
    (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [System.String[]]
        [System.IO.FileInfo[]]
        $Path
    )

    process
    {
        foreach ($filePath in $Path)
        {
            $tokens, $parseErrors = $null

            $ast = [System.Management.Automation.Language.Parser]::ParseFile($filePath, [ref] $tokens, [ref] $parseErrors)

            if ($parseErrors)
            {
                $PSCmdlet.ThrowTerminatingError(
                    [System.Management.Automation.ErrorRecord]::new(
                        ($script:localizedData.FailedParseScriptAst -f $parseErrors[0].Message),
                        'GAD0001', # cSpell: disable-line
                        [System.Management.Automation.ErrorCategory]::InvalidOperation,
                        $filePath
                    )
                )
            }

            if ($ast)
            {
                $ast
            }
        }
    }
}
#EndRegion '.\Private\Get-AstDefinition.ps1' 71
#Region '.\Private\Get-CommandAst.ps1' -1

<#
    .SYNOPSIS
        Retrieves the abstract syntax trees (AST's) of a PowerShell command.
 
    .DESCRIPTION
        The Get-CommandAst function retrieves the abstract syntax tree (AST) of a
        PowerShell command. The AST represents the structure of the command and
        can be used for further analysis or manipulation.
 
    .PARAMETER Ast
        Specifies the AST of a script block.
 
    .PARAMETER CommandName
        Specifies the PowerShell command for which to retrieve the AST.
 
    .EXAMPLE
        Get-CommandAst -CommandName 'Should'
 
        This example retrieves the AST of the 'Should' command.
 
    .INPUTS
        [System.Collections.Generic.IEnumerable`1[System.Management.Automation.Language.Ast]]
 
        The AST of a script block.
 
    .OUTPUTS
        System.Management.Automation.Language.CommandAst[]
 
        The function returns the abstract syntax trees (AST's) of the specified PowerShell command.
#>

function Get-CommandAst
{
    [CmdletBinding()]
    [OutputType([System.Collections.Generic.IEnumerable`1[System.Management.Automation.Language.Ast]])]
    param
    (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [System.Management.Automation.Language.Ast]
        $Ast,

        [Parameter(Mandatory = $true)]
        [System.String]
        $CommandName
    )

    process
    {
        Write-Debug -Message ($script:localizedData.Get_CommandAst_Debug_RetrievingCommandAsts -f $CommandName)

        $commandAsts = $Ast.FindAll({
                param
                (
                    [Parameter()]
                    $node
                )

                return $node -is [System.Management.Automation.Language.CommandAst] -and $node.GetCommandName() -eq $CommandName
            }, $true)

        return $commandAsts
    }
}
#EndRegion '.\Private\Get-CommandAst.ps1' 63
#Region '.\Private\Get-PesterCommandParameter.ps1' -1

<#
    .SYNOPSIS
        Get all the parameters of a Pester command.
 
    .DESCRIPTION
        The Get-PesterCommandParameter function returns all of parameter command
        elements.
 
    .PARAMETER CommandAst
        Specifies the CommandAst object representing the command.
 
    .PARAMETER CommandName
        Specifies the name of the command.
 
    .PARAMETER IgnoreParameter
        Specifies all the parameters that should be ignored.
 
    .PARAMETER NamedParameter
        Specifies all the names of the parameters that are not positional, that
        have a value associated with them.
 
    .PARAMETER PositionalParameter
        Specifies all the names of the positional parameters. Must be specified
        in the order of their numeric position.
 
    .OUTPUTS
        System.Collections.Hashtable
 
        Holds all the parameters of the CommandAst.
 
    .EXAMPLE
        $commandAst = [System.Management.Automation.Language.Parser]::ParseInput('Should -Be "ExpectedString" "BecauseString" "ActualString"')
        Get-PesterCommandParameter -CommandAst $commandAst -CommandName 'Should' -IgnoreParameter @('Be', 'Not') -PositionalParameter @('ExpectedValue', 'Because', 'ActualValue')
 
        Returns a hashtable with the parameters.
#>

function Get-PesterCommandParameter
{
    [CmdletBinding()]
    [OutputType([System.Collections.Hashtable])]
    param
    (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [System.Management.Automation.Language.CommandAst]
        $CommandAst,

        [Parameter(Mandatory = $true)]
        [System.String]
        $CommandName,

        [Parameter()]
        [System.String[]]
        $IgnoreParameter = @(),

        [Parameter()]
        [System.String[]]
        $NamedParameter = @(),

        [Parameter()]
        [System.String[]]
        $PositionalParameter = @()
    )

    process
    {
        Write-Debug -Message ($script:localizedData.Get_PesterCommandParameter_Debug_RetrievingParameters -f $CommandAst.Extent.Text)
        Write-Debug -Message ($script:localizedData.Get_PesterCommandParameter_Debug_RetrievingCommandName -f $CommandName)

        # Filter out the command name from the command elements.
        $commandElement = $CommandAst.CommandElements |
            Where-Object -FilterScript {
                -not (
                    $_ -is [System.Management.Automation.Language.StringConstantExpressionAst] `
                        -and $_.Extent.Text -eq $CommandName
                )
            }

        Write-Debug -Message ($script:localizedData.Get_PesterCommandParameter_Debug_IgnoreParameters -f ($IgnoreParameter -join ', '))

        <#
            Filter out the parameters to ignore from the command elements, e.g.:
                - Be
                - Not
        #>

        $commandElement = $commandElement |
            Where-Object -FilterScript {
                # Calls ConvertTo-ActualParameterName to handle abbreviated parameter names.
                -not (
                    $_ -is [System.Management.Automation.Language.CommandParameterAst] `
                        -and (ConvertTo-ActualParameterName -NamedParameter $_.ParameterName -CommandName $CommandName) -in $IgnoreParameter
                )
            }

        # Build a hashtable based on the values in $PositionalParameter and $NamedParameter.
        $parameterHashtable = @{}

        if (${commandElement}?.Count -gt 0)
        {
            Write-Debug -Message ($script:localizedData.Get_PesterCommandParameter_Debug_NamedParameters -f ($NamedParameter -join ', '))

            <#
                Filter out the named parameters including its values from the command elements, e.g.:
                    - ActualValue
                    - ExpectedValue
                    - Because
            #>

            $parameterElements = $commandElement.Where({
                    $result = $false

                    if ($_ -is [System.Management.Automation.Language.CommandParameterAst])
                    {
                        $actualParameterName = ConvertTo-ActualParameterName -NamedParameter $_.ParameterName -CommandName $CommandName

                        # Search for named parameters including positional parameters that too can be set as named parameters.
                        $result = $actualParameterName -in $PositionalParameter -or $actualParameterName -in $NamedParameter
                    }

                    $result
                })

            $filterCommandElements = @()

            foreach ($parameterElement in $parameterElements)
            {
                $parameterIndex = $commandElement.IndexOf($parameterElement)

                # Above returned -1 if parameter name was not found.
                if ($parameterIndex -ne -1)
                {
                    $convertToActualParameterNameParameters = @{
                        CommandName    = $CommandName
                        NamedParameter = $commandElement[$parameterIndex].ParameterName
                    }

                    # Handle abbreviated parameter names.
                    $parameterName = ConvertTo-ActualParameterName @convertToActualParameterNameParameters

                    $parameterHashtable.$parameterName = @{
                        Position   = 0
                        Positional = $false
                        ExtentText = $commandElement[$parameterIndex + 1].Extent.Text
                    }

                    $filterCommandElements += $commandElement[$parameterIndex]
                    $filterCommandElements += $commandElement[$parameterIndex + 1]
                }
            }

            # Filter out the value parameter and its value from the command elements.
            $commandElement = $commandElement |
                Where-Object -FilterScript {
                    $_ -notin $filterCommandElements
                }
        }

        # Get the positional parameters extent text that are left (if any).
        if (${commandElement}?.Count -gt 0)
        {
            Write-Debug -Message ($script:localizedData.Get_PesterCommandParameter_Debug_PositionalParameters -f ($PositionalParameter -join ', '))

            $elementCounter = 0
            $positionalCounter = 1

            # Positional parameters are discovered in the order they are specified in $PositionalParameter.
            foreach ($parameter in $PositionalParameter)
            {
                # Only add the positional parameter if it does not already exist in the hashtable.
                if (-not $parameterHashtable.ContainsKey($parameter))
                {
                    # Only add positional parameter if there actually a value for it.
                    $parameterHashtable.$parameter = @{
                        Position   = $positionalCounter++
                        Positional = $true
                        ExtentText = $commandElement[$elementCounter++].Extent.Text
                    }

                    # If the command element is $null then there are no more positional parameters to process.
                    if ($null -eq $commandElement[$elementCounter])
                    {
                        break
                    }
                }
            }
        }

        return $parameterHashtable
    }
}
#EndRegion '.\Private\Get-PesterCommandParameter.ps1' 189
#Region '.\Private\Get-PesterCommandSyntaxVersion.ps1' -1

<#
    .SYNOPSIS
        Determines the Pester command syntax version based on the command and
        parameter name.
 
    .DESCRIPTION
        This function checks the command and parameter name used in a Pester command
        to determine the syntax version of the command. It supports identifying syntax
        versions based on specific commands and parameters.
 
    .PARAMETER CommandAst
        The abstract syntax tree of the command being analyzed.
 
    .PARAMETER CommandName
        The name of the command to check for in the AST. This allows for dynamic
        checking of different commands.
 
    .PARAMETER ParameterName
        The name of the parameter to check for in the command. This allows for
        dynamic checking of different parameters.
 
    .EXAMPLE
        $ast = [System.Management.Automation.Language.Parser]::ParseInput('Should -BeExactly "value"', [ref]$null, [ref]$null)
        Get-PesterCommandSyntaxVersion -CommandAst $ast
 
        Returns the syntax version for the 'Should -BeExactly' command.
#>

function Get-PesterCommandSyntaxVersion
{
    [CmdletBinding()]
    [OutputType([System.Int32])]
    param
    (
        [Parameter(Mandatory = $true)]
        [System.Management.Automation.Language.CommandAst]
        $CommandAst
    )

    $sourceSyntaxVersion = $null

    if ($CommandAst.CommandElements[0].Extent.Text -match 'Should-\w+\b')
    {
        $sourceSyntaxVersion = 6
    }
    elseif ($CommandAst.CommandElements[0].Extent.Text -eq 'Should' -and (Get-ShouldCommandOperatorName -CommandAst $CommandAst))
    {
        $sourceSyntaxVersion = 5
    }

    return $sourceSyntaxVersion
}
#EndRegion '.\Private\Get-PesterCommandSyntaxVersion.ps1' 52
#Region '.\Private\Get-PipelineBeforeShould.ps1' -1

<#
    .SYNOPSIS
        Retrieves the script block associated with a pipeline or parameter.
 
    .DESCRIPTION
        The Get-PipelineBeforeShould function is used to retrieve the script block
        associated with a pipeline or parameter. It can be used to extract the script
        block from a pipeline or from a specific parameter.
 
    .PARAMETER CommandAst
        The CommandAst parameter specifies the command AST (Abstract Syntax Tree)
        object from which the script block is to be retrieved.
 
    .PARAMETER ParameterName
        Specifies the name of the parameter whose script block is to be retrieved.
 
    .PARAMETER ParsePipeline
        Specifies whether to parse the pipeline to find the script block.
 
    .OUTPUTS
        System.String
 
        The function returns the text of the script block if found, otherwise it returns $null.
 
    .EXAMPLE
        Get-PipelineBeforeShould -CommandAst $commandAst -ParameterName 'ActualValue' -ParsePipeline
 
        Retrieves the script block associated with the specified command AST and
        parameter name, parsing the pipeline if necessary.
#>

function Get-PipelineBeforeShould
{
    [CmdletBinding()]
    [OutputType([System.String])]
    param
    (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [System.Management.Automation.Language.CommandAst]
        $CommandAst,

        [Parameter()]
        [System.String]
        $ParameterName,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $ParsePipeline
    )

    process
    {
        # Initialize the scriptblock variable
        $scriptBlock = $null

        # If scriptblock is not found in the pipeline, look for it in the parameters
        if ($ParameterName)
        {
            # Find the parameter by name
            $commandParameterAst = $CommandAst.CommandElements |
                Where-Object -FilterScript {
                    $_ -is [System.Management.Automation.Language.CommandParameterAst] -and
                    $_.ParameterName -eq $ParameterName
                }

            if ($commandParameterAst)
            {
                $commandParameterIndex = $commandParameterAst.Parent.CommandElements.IndexOf($commandParameterAst)

                # Assuming the next element is the argument to the parameter
                $argumentAst = $commandParameterAst.Parent.CommandElements[$commandParameterIndex + 1]

                # Retrieve the argument
                $scriptBlock = $argumentAst.Extent.Text
            }
        }

        # Check if we need to parse the pipeline
        if (-not $scriptBlock -and $ParsePipeline.IsPresent)
        {
            # Attempt to find a pipeline before the CommandAst in the script
            $pipelineAst = $CommandAst.Parent

            # Only get the scriptblock if the pipeline has more than one element
            if ($pipelineAst -is [System.Management.Automation.Language.PipelineAst] -and $pipelineAst.PipelineElements.Count -gt 1)
            {
                # If a pipeline is found, get all the pipeline elements except the one that is the CommandAst
                $lastPipelineElement = $pipelineAst.PipelineElements[-1]
                $scriptBlock = $pipelineAst.Extent.Text.Replace($lastPipelineElement.Extent.Text, '').TrimEnd(" |`r`n")
            }
        }

        # Return the scriptblock's text if found, otherwise return null
        return $scriptBlock
    }
}
#EndRegion '.\Private\Get-PipelineBeforeShould.ps1' 96
#Region '.\Private\Get-ShouldCommandOperatorName.ps1' -1

<#
.SYNOPSIS
    Retrieves the Should command operator based on the provided CommandAst.
 
.DESCRIPTION
    The Get-ShouldCommandOperatorName function retrieves the Should command operator based
    on the provided CommandAst object. It searches for specific operators and their
    aliases in the CommandAst and returns the corresponding operator name.
 
.PARAMETER CommandAst
    Specifies the CommandAst object representing the command for which the Should
    operator needs to be retrieved.
 
.OUTPUTS
    System.String
 
    The Should command operator name.
 
.EXAMPLE
    $commandAst = [System.Management.Automation.Language.Parser]::ParseInput('Should -Be "Hello"')
    Get-ShouldCommandOperatorName -CommandAst $commandAst
 
    Returns "Be"
#>


function Get-ShouldCommandOperatorName
{
    [CmdletBinding()]
    [OutputType([System.String])]
    param
    (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [System.Management.Automation.Language.CommandAst]
        $CommandAst
    )

    process
    {
        # Operators. Output from Pester's command Get-ShouldOperator.
        $possibleShouldOperator = @(
            'Be',
            'BeExactly',
            'BeGreaterThan',
            'BeLessOrEqual',
            'BeIn',
            'BeLessThan',
            'BeGreaterOrEqual',
            'BeLike',
            'BeLikeExactly',
            'BeNullOrEmpty',
            'BeOfType',
            'BeTrue',
            'BeFalse',
            'Contain',
            'Exist',
            'FileContentMatch',
            'FileContentMatchExactly',
            'FileContentMatchMultiline',
            'FileContentMatchMultilineExactly',
            'HaveCount',
            'HaveParameter',
            'Match',
            'MatchExactly',
            'Throw',
            'InvokeVerifiable',
            'Invoke'
        )

        # Operator aliases. Output from Pester's command Get-ShouldOperator.
        $possibleShouldOperatorAlias = @{
            'EQ'       = 'Be'
            'CEQ'      = 'BeExactly'
            'GT'       = 'BeGreaterThan'
            'LE'       = 'BeLessOrEqual'
            'LT'       = 'BeLessThan'
            'GE'       = 'BeGreaterOrEqual'
            'HaveType' = 'BeOfType'
            'CMATCH'   = 'MatchExactly'
        }

        $shouldOperatorAsts = $CommandAst.Find({
                param
                (
                    [Parameter()]
                    $node
                )

                return $node -is [System.Management.Automation.Language.CommandParameterAst] -and ($node.ParameterName -in $possibleShouldOperator -or ($possibleShouldOperatorAlias -and $node.ParameterName -in $possibleShouldOperatorAlias.Keys))
            }, $true)

        if (${shouldOperatorAsts}?.ParameterName -in ${possibleShouldOperatorAlias}?.Keys)
        {
            return $possibleShouldOperatorAlias[$shouldOperatorAsts.ParameterName]
        }

        return ${shouldOperatorAsts}?.ParameterName
    }
}
#EndRegion '.\Private\Get-ShouldCommandOperatorName.ps1' 99
#Region '.\Private\Test-IsPipelinePart.ps1' -1


<#
    .SYNOPSIS
        Determines if a command is part of a pipeline.
 
    .DESCRIPTION
        The Test-IsPipelinePart function checks if a given command is part of a
        pipeline. It examines the parent of the CommandAst and determines if it
        is a PipelineAst.
 
    .PARAMETER CommandAst
        The CommandAst object representing the command to be checked.
 
    .EXAMPLE
        Test-IsPipelinePart -CommandAst $commandAst
 
        Determines if the specified command is part of a pipeline.
 
    .OUTPUTS
        System.Boolean
 
        Returns $true if the command is part of a pipeline, otherwise returns $false.
#>

function Test-IsPipelinePart
{
    [CmdletBinding()]
    [OutputType([System.Boolean])]
    param
    (
        [Parameter(Mandatory = $true)]
        [System.Management.Automation.Language.CommandAst]
        $CommandAst
    )

    # Check if the parent of the CommandAst is a PipelineAst
    $isPartOfPipeline = $CommandAst.Parent -and $CommandAst.Parent -is [System.Management.Automation.Language.PipelineAst] -and $CommandAst.Parent.PipelineElements.Count -gt 1

    # Return true if part of a pipeline, false otherwise
    return $isPartOfPipeline
}
#EndRegion '.\Private\Test-IsPipelinePart.ps1' 41
#Region '.\Private\Test-PesterCommandNegated.ps1' -1

<#
    .SYNOPSIS
        Determines if a Pester command is negated.
 
    .DESCRIPTION
        The Test-PesterCommandNegated function is used to determine if a Pester
        command is negated. It searches for the 'Not' parameter in the CommandAst
        and also handles the scenario where the 'Not' parameter is specifically
        set to $false.
 
    .PARAMETER CommandAst
        The CommandAst object representing the Pester command.
 
    .EXAMPLE
        $commandAst = [System.Management.Automation.Language.Parser]::ParseInput('Should -Not -Be "Test"')
        Test-PesterCommandNegated -CommandAst $commandAst
 
        Returns $true
 
    .EXAMPLE
        $commandAst = [System.Management.Automation.Language.Parser]::ParseInput('Should -Be "Test"')
        Test-PesterCommandNegated -CommandAst $commandAst
 
        Returns $false
 
    .INPUTS
        System.Management.Automation.Language.CommandAst
 
    .OUTPUTS
        System.Boolean
#>

function Test-PesterCommandNegated
{
    [CmdletBinding()]
    [OutputType([System.Boolean])]
    param
    (
        [Parameter(Mandatory = $true)]
        [System.Management.Automation.Language.CommandAst]
        $CommandAst
    )

    if ($CommandAst.Parent -is [System.Management.Automation.Language.PipelineAst])
    {
        # Assuming the last element in the pipeline is the command we are interested in.
        $CommandAst = $CommandAst.Parent.PipelineElements[-1]
    }

    $negateCommandParameterAst = ${CommandAst}?.CommandElements |
        Where-Object -FilterScript {
            $_ -is [System.Management.Automation.Language.CommandParameterAst] `
                -and $_.ParameterName -eq 'Not' `
                -and $_.Argument.Extent.Text -ne '$false'
        }

    $negated = $negateCommandParameterAst ? $true : $false

    return $negated
}
#EndRegion '.\Private\Test-PesterCommandNegated.ps1' 60
#Region '.\Public\Convert-PesterSyntax.ps1' -1

<#
    .SYNOPSIS
        Converts the syntax of a file to the syntax of a newer Pester version.
 
    .DESCRIPTION
        The Convert-PesterSyntax command is used to convert the syntax of a file to
        the syntax of a newer Pester version.. It supports converting to Pester 6 format.
 
    .PARAMETER Path
        Specifies the path of the file(s) to be converted. This parameter is mandatory
        and accepts a string or a FileInfo object.
 
    .PARAMETER Pester6
        Specifies that the syntax to convert to is Pester 6. This parameter is
        mandatory to convert to Pester 6 syntax.
 
    .PARAMETER UseNamedParameters
        Specifies whether to use named parameters in the converted syntax.
 
    .PARAMETER UsePositionalParameters
        Specifies whether to use positional parameters in the converted syntax,
        where supported.
 
    .PARAMETER Force
        Specifies that the file should be created without any confirmation.
 
    .PARAMETER PassThru
        Returns the script after converting the syntax. This parameter is most
        useful when passing in a single file to convert. If multiple files are
        passed in, the script of all the files will be returned as an array.
        If PassThru is specified, no file will not be modified.
 
    .PARAMETER OutputPath
        Specifies the path to save the converted file(s). If this parameter is
        not specified, the original file(s) will be overwritten.
 
    .EXAMPLE
        Convert-PesterSyntax -Path "C:\Scripts\Test.ps1" -Pester6
 
        Converts the syntax of the Test.ps1 file to Pester 6 syntax.
 
    .EXAMPLE
        Get-ChildItem -Path "C:\Scripts" -Recurse -Filter "*.ps1" | Convert-PesterSyntax -Pester6
 
        Converts the syntax of all PowerShell files in the C:\Scripts directory and
        its subdirectories to Pester 6 syntax.
 
    .EXAMPLE
        Convert-PesterSyntax -Path (Get-ChildItem -Path "C:\Scripts" -Recurse -Filter "*.ps1") -Pester6
 
        Converts the syntax of all PowerShell files in the C:\Scripts directory and
        its subdirectories to Pester 6 syntax.
#>

function Convert-PesterSyntax
{
    [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidMultipleTypeAttributes', '', Justification = 'We want to pass in both strings and FileInfo objects to parameter Path.')]
    [CmdletBinding(DefaultParameterSetName = 'Pester6', SupportsShouldProcess = $true, ConfirmImpact = 'High')]
    param
    (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [System.String[]]
        [System.IO.FileInfo[]]
        $Path,

        [Parameter(ParameterSetName = 'Pester6')]
        [System.Management.Automation.SwitchParameter]
        $Pester6,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $UseNamedParameters,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $UsePositionalParameters,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $Force,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $PassThru,

        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [System.String]
        $OutputPath
    )

    begin
    {
        if (($Force.IsPresent -and -not $Confirm) -or $PassThru.IsPresent)
        {
            $ConfirmPreference = 'None'
        }

        $assertBoundParameterParameters = @{
            BoundParameterList     = $PSBoundParameters
            MutuallyExclusiveList1 = @('UseNamedParameters')
            MutuallyExclusiveList2 = @('UsePositionalParameters')
        }

        Assert-BoundParameter @assertBoundParameterParameters

        $assertBoundParameterParameters = @{
            BoundParameterList     = $PSBoundParameters
            MutuallyExclusiveList1 = @('PassThru')
            MutuallyExclusiveList2 = @('OutputPath')
        }

        Assert-BoundParameter @assertBoundParameterParameters

        if ($OutputPath)
        {
            if (-not (Test-Path -Path $OutputPath))
            {
                $PSCmdlet.ThrowTerminatingError(
                    [System.Management.Automation.ErrorRecord]::new(
                        $script:localizedData.Convert_PesterSyntax_OutputPathDoesNotExist -f $OutputPath,
                        'CPS0002', # cSpell: disable-line
                        [System.Management.Automation.ErrorCategory]::InvalidArgument,
                        $OutputPath
                    )
                )
            }

            if ((Test-Path -Path $OutputPath) -and (Get-Item -Path $OutputPath).PSIsContainer -eq $false)
            {
                $PSCmdlet.ThrowTerminatingError(
                    [System.Management.Automation.ErrorRecord]::new(
                        $script:localizedData.Convert_PesterSyntax_OutputPathIsNotDirectory -f $OutputPath,
                        'CPS0003', # cSpell: disable-line
                        [System.Management.Automation.ErrorCategory]::InvalidArgument,
                        $OutputPath
                    )
                )
            }
        }

        $convertParameters = @{} + $PSBoundParameters
        $convertParameters.Remove('Path')
        $convertParameters.Remove('Force')
        $convertParameters.Remove('PassThru')
        $convertParameters.Remove('OutputPath')

        if ($PSCmdlet.ParameterSetName -eq 'Pester6' -and -not $Pester6.IsPresent)
        {
            $Pester6 = $true
            $convertParameters.Pester6 = $true
        }

        if ($Pester6.IsPresent)
        {
            Write-Verbose -Message $script:localizedData.Convert_PesterSyntax_StartPester6Conversion
        }
        else
        {
            $PSCmdlet.ThrowTerminatingError(
                [System.Management.Automation.ErrorRecord]::new(
                    $script:localizedData.Convert_PesterSyntax_NoVersionSpecified,
                    'CPS0001', # cSpell: disable-line
                    [System.Management.Automation.ErrorCategory]::InvalidOperation,
                    $null
                )
            )
        }
    }

    process
    {
        $writeProgressId1Parameters = @{
            Id       = 1
            Activity = $script:localizedData.Convert_PesterSyntax_WriteProgress_Id1_Activity
        }

        if ($Path.Count -gt 1)
        {
            Write-Progress @writeProgressId1Parameters -PercentComplete 0 -Status ($script:localizedData.Convert_PesterSyntax_WriteProgress_Id1_Status_ProcessingFiles -f $Path.Count)
        }
        else
        {
            Write-Progress @writeProgressId1Parameters -PercentComplete 0 -Status ($script:localizedData.Convert_PesterSyntax_WriteProgress_Id1_Status_ProcessingFile -f (Split-Path -Path $Path -Leaf))
        }

        foreach ($filePath in $Path)
        {
            if ($Path.Count -gt 1)
            {
                Write-Progress @writeProgressId1Parameters -PercentComplete (($Path.IndexOf($filePath) / $Path.Count) * 100) -Status ($script:localizedData.Convert_PesterSyntax_WriteProgress_Id1_Status_ProcessingFile -f (Split-Path -Path $filePath -Leaf))
            }

            $verboseDescriptionMessage = $script:localizedData.Convert_PesterSyntax_ShouldProcessVerboseDescription -f $filePath
            $verboseWarningMessage = $script:localizedData.Convert_PesterSyntax_ShouldProcessVerboseWarning -f $filePath
            $captionMessage = $script:localizedData.Convert_PesterSyntax_ShouldProcessCaption

            if (-not ($PSCmdlet.ShouldProcess($verboseDescriptionMessage, $verboseWarningMessage, $captionMessage)))
            {
                continue
            }

            if ($filePath -is [System.String])
            {
                $filePath = Convert-Path -Path $filePath
            }

            $scriptBlockAst = $filePath | Get-AstDefinition -ErrorAction 'Stop'

            # Get the script text from the script block AST that will be used to replace the original script text.
            $convertedScriptText = $scriptBlockAst.Extent.Text

            Write-Debug -Message ($script:localizedData.Convert_PesterSyntax_Debug_ScriptBlockAst -f $scriptBlockAst.Extent.Text)

            <#
                Get all the Should command AST's in the script block AST, and sort
                them by their start offset in descending order. The descending order
                is so that we can replace the original extent text with the new extent
                without reloading the script block AST.
            #>

            $shouldCommandAst = $scriptBlockAst |
                Get-CommandAst -CommandName 'Should' -ErrorAction 'Stop' |
                Sort-Object -Property { $_.Extent.StartOffset } -Descending

            if ($shouldCommandAst)
            {
                $writeProgressId2Parameters = @{
                    Id       = 2
                    ParentId = 1
                    Activity = $script:localizedData.Convert_PesterSyntax_WriteProgress_Id2_Activity
                }

                Write-Progress @writeProgressId2Parameters -PercentComplete 0 -Status ($script:localizedData.Convert_PesterSyntax_WriteProgress_Id2_Status_ProcessingCommands -f $shouldCommandAst.Count)

                Write-Debug -Message ($script:localizedData.Convert_PesterSyntax_Debug_FoundShouldCommand -f $shouldCommandAst.Count, $filePath)

                foreach ($commandAst in $shouldCommandAst)
                {
                    $apply = $true

                    # Get start and end offsets of commandAst.Extent
                    $startOffset = $commandAst.Extent.StartOffset
                    $endOffset = $commandAst.Extent.EndOffset

                    # If only one item was returned then there is no collection that has the method IndexOf.
                    $percentComplete = $shouldCommandAst.Count -gt 1 ? (($shouldCommandAst.IndexOf($commandAst) / $shouldCommandAst.Count) * 100) : 100

                    Write-Progress @writeProgressId2Parameters -PercentComplete $percentComplete -Status ($script:localizedData.Convert_PesterSyntax_WriteProgress_Id2_Status_ProcessingLine -f $commandAst.Extent.StartLineNumber)

                    $operatorName = Get-ShouldCommandOperatorName -CommandAst $commandAst -ErrorAction 'Stop'

                    if ($operatorName)
                    {
                        switch ($operatorName)
                        {
                            'Be'
                            {
                                $newExtentText = Convert-ShouldBe -CommandAst $commandAst @convertParameters -ErrorAction 'Stop'

                                break
                            }

                            'BeExactly'
                            {
                                $newExtentText = Convert-ShouldBeExactly -CommandAst $commandAst @convertParameters -ErrorAction 'Stop'

                                break
                            }

                            'BeFalse'
                            {
                                $newExtentText = Convert-ShouldBeFalse -CommandAst $commandAst @convertParameters -ErrorAction 'Stop'

                                break
                            }

                            'BeGreaterOrEqual'
                            {
                                $newExtentText = Convert-ShouldBeGreaterOrEqual -CommandAst $commandAst @convertParameters -ErrorAction 'Stop'

                                break
                            }

                            'BeGreaterThan'
                            {
                                $newExtentText = Convert-ShouldBeGreaterThan -CommandAst $commandAst @convertParameters -ErrorAction 'Stop'

                                break
                            }

                            'BeIn'
                            {
                                $newExtentText = Convert-ShouldBeIn -CommandAst $commandAst @convertParameters -ErrorAction 'Stop'

                                if ((Test-IsPipelinePart -CommandAst $commandAst -ErrorAction 'Stop'))
                                {
                                    # Change start and end offsets to replace the entire commandAst.Parent.Extent.Text.
                                    $startOffset = $commandAst.Parent.Extent.StartOffset
                                    $endOffset = $commandAst.Parent.Extent.EndOffset
                                }

                                break
                            }

                            'BeLessOrEqual'
                            {
                                $newExtentText = Convert-ShouldBeLessOrEqual -CommandAst $commandAst @convertParameters -ErrorAction 'Stop'

                                break
                            }

                            'BeLessThan'
                            {
                                $newExtentText = Convert-ShouldBeLessThan -CommandAst $commandAst @convertParameters -ErrorAction 'Stop'

                                break
                            }

                            'BeLike'
                            {
                                $newExtentText = Convert-ShouldBeLike -CommandAst $commandAst @convertParameters -ErrorAction 'Stop'

                                break
                            }

                            'BeLikeExactly'
                            {
                                $newExtentText = Convert-ShouldBeLikeExactly -CommandAst $commandAst @convertParameters -ErrorAction 'Stop'

                                break
                            }


                            'BeNullOrEmpty'
                            {
                                $newExtentText = Convert-ShouldBeNullOrEmpty -CommandAst $commandAst @convertParameters -ErrorAction 'Stop'

                                break
                            }

                            'BeOfType'
                            {
                                $newExtentText = Convert-ShouldBeOfType -CommandAst $commandAst @convertParameters -ErrorAction 'Stop'

                                break
                            }

                            'BeTrue'
                            {
                                $newExtentText = Convert-ShouldBeTrue -CommandAst $commandAst @convertParameters -ErrorAction 'Stop'

                                break
                            }

                            'Contain'
                            {
                                $newExtentText = Convert-ShouldContain -CommandAst $commandAst @convertParameters -ErrorAction 'Stop'

                                break
                            }

                            'Match'
                            {
                                $newExtentText = Convert-ShouldMatch -CommandAst $commandAst @convertParameters -ErrorAction 'Stop'

                                break
                            }

                            'MatchExactly'
                            {
                                $newExtentText = Convert-ShouldMatchExactly -CommandAst $commandAst @convertParameters -ErrorAction 'Stop'

                                break
                            }

                            'Throw'
                            {
                                $isNegated = Test-PesterCommandNegated -CommandAst $commandAst

                                if ($isNegated)
                                {
                                    $newExtentText = Convert-ShouldNotThrow -CommandAst $commandAst @convertParameters -ErrorAction 'Stop'

                                    # Change start and end offsets to replace the entire commandAst.Parent.Extent.Text.
                                    $startOffset = $commandAst.Parent.Extent.StartOffset
                                    $endOffset = $commandAst.Parent.Extent.EndOffset
                                }
                                else
                                {
                                    $newExtentText = Convert-ShouldThrow -CommandAst $commandAst @convertParameters -ErrorAction 'Stop'
                                }

                                break
                            }

                            default
                            {
                                Write-Warning -Message ($script:localizedData.Convert_PesterSyntax_Warning_UnsupportedCommandOperator -f $operatorName, $commandAst.Extent.Text)

                                $apply = $false
                            }
                        }
                    }
                    else
                    {
                        Write-Warning -Message ($script:localizedData.Convert_PesterSyntax_MissingSupportedCommandOperator -f $commandAst.Extent.Text)
                    }

                    if ($apply)
                    {
                        # Replace the portion of the script.
                        $convertedScriptText = $convertedScriptText.Remove($startOffset, $endOffset - $startOffset).Insert($startOffset, $newExtentText)
                    }
                }

                Write-Progress @writeProgressId2Parameters -Completed -PercentComplete 100 -Status $script:localizedData.Convert_PesterSyntax_WriteProgress_Id2_Status_Completed
            }
            else
            {
                Write-Verbose -Message ($script:localizedData.Convert_PesterSyntax_NoShouldCommand -f $filePath)
            }

            if ($PassThru)
            {
                $convertedScriptText
            }
            else
            {
                if ($OutputPath)
                {
                    $newFilePath = Join-Path -Path $OutputPath -ChildPath (Split-Path -Path $filePath -Leaf)

                    Set-Content -Path $newFilePath -Value $convertedScriptText -NoNewLine -ErrorAction 'Stop'
                }
                else
                {
                    Set-Content -Path $filePath -Value $convertedScriptText -NoNewLine -ErrorAction 'Stop'
                }
            }
        }
    }

    end
    {
        Write-Progress @writeProgressId1Parameters -Completed -PercentComplete 100 -Status $script:localizedData.Convert_PesterSyntax_WriteProgress_Id1_Status_Completed
    }
}
#EndRegion '.\Public\Convert-PesterSyntax.ps1' 447