Transpilers/Syntax/EqualityTypeComparison.psx.ps1

<#
.SYNOPSIS
    Allows equality type comparison.
.DESCRIPTION
    Allows most equality comparison using triple equals (===).

    Many languages support this syntax. PowerShell does not.

    This transpiler enables equality and type comparison with ===.
.NOTES
    This will not work if there is a constant on both sides of the expression

    
    if ($one === $one) { "this will work"}
    if ('' === '') { "this will not"}
    
.EXAMPLE
    Invoke-PipeScript -ScriptBlock {
        $a = 1
        $number = 1
        if ($a === $number ) {
            "A is $a"
        }
    }
.EXAMPLE
    Invoke-PipeScript -ScriptBlock {
        $One = 1
        $OneIsNotANumber = "1"
        if ($one == $OneIsNotANumber) {
            'With ==, a number can be compared to a string, so $a == "1"'
        }
        if (-not ($One === $OneIsNotANumber)) {
            "With ===, a number isn't the same type as a string, so this will be false."
        }
    }
.EXAMPLE
    Invoke-PipeScript -ScriptBlock {
        if ($null === $null) {
            '$Null really is $null'
        }
    }
.EXAMPLE
    Invoke-PipeScript -ScriptBlock {
        $zero = 0
        if (-not ($zero === $null)) {
            '$zero is not $null'
        }
    }
.EXAMPLE
    {
        $a = "b"
        $a === "b"
    } | .>PipeScript
#>

[ValidateScript({
    # This is valid if the assignment statement's
    $AssignmentStatementAST = $_
    # The operator must be an equals
    $AssignmentStatementAST.Operator -eq 'Equals' -and     
    # The right must start with =
    $AssignmentStatementAST.Right -match '^==' -and
    # There must not be space between it and the left
    $AssignmentStatementAST.Parent.ToString() -match "$(
        [Regex]::Escape($AssignmentStatementAST.Left.ToString())
    )\s{0,}===[^=]"

})]
param(
# The original assignment statement.
[Parameter(Mandatory,ValueFromPipeline)]
[Management.Automation.Language.AssignmentStatementAst]
$AssignmentStatementAST
)

process {
    if ($AssignmentStatementAST.Left -isnot [Management.Automation.Language.VariableExpressionAST]) {
        Write-Error "Left side of EqualityTypeComparison must be a variable"
        return        
    }
    $leftSide = $AssignmentStatementAST.Left

    foreach ($side in 'Left', 'Right') {        
        $ExecutionContext.SessionState.PSVariable.Set("${side}Side", $AssignmentStatementAST.$side)
    }    
    
    $rightSide = $rightSide -replace '^=='

    # We create a new script by:
    $newScript =
        # Checking for the existence of GetType on both objects (and the same result from each)
        "(
    (-not $leftSide.GetType -and -not $rightSide.GetType) -or
    (
        (
            ($leftSide.GetType -and $rightSide.GetType) -and
            ($leftSide.GetType() -eq $rightSide.GetType()
        ) -and ("
 +
        # then, in a new subexpression
        [Environment]::Newline +
        # taking the left side as-is.
        $AssignmentStatementAST.Left.Extent.ToString() + 
        # replacing the = with ' -eq '
        ' -eq ' +
        # And replacing any the = and any trailing whitespace.
        ($AssignmentStatementAST.Right.Extent.ToString() -replace '^==\s{1,}') + ")
        )
    )
)"

    
    [scriptblock]::Create($newScript)
}