Skip to content

PSUseConsistentIndentation indents inconsistently in function body after param block #1241

Closed

Description

@rjmholt

From Eric Marquez (@ebmarquez) in PowerShell/vscode-powershell#1958.

Repro:

$script = @'
function verb-noun {
    <#
        .SYNOPSIS
        example

        .INPUTS
        String
        System.Management.Automation.PSCredential

        .OUTPUTS
        System.Management.Automation.PSCustomObject

        .NOTES

    #>
    [CmdLetBinding()]
    [OutputType([PSCustomObject])]
    Param(

        # Computer
        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String]
        $Computer,

        # Credential
        [Parameter(Mandatory = $true)]
        [System.Management.Automation.PSCredential]
        $Credential
    )

    $cmd = Get-ShowCommands | Where-Object { $_.Name -eq 'running-config' }
$result = Invoke-NetDeviceShowCommand -Computer $Computer -Credential $Credential -Command $cmd.CommandLine
Add-Member -InputObject $result -MemberType NoteProperty -Name "Name" -Value $cmd.Name
return $result
'@

$PSUseConsistentIndentation = @{ 
            Enable = 'true'
            IndentationSize     = 4;
             PipelineIndentation = 'IncreaseIndentationForFirstPipeline'; 
             Kind                = 'space'
        }
$rules = @{
    PSUseConsistentIndentation = $PSUseConsistentIndentation;
}

Invoke-Formatter -ScriptDefinition $script -Settings @{ 
    IncludeRules = @('PSUserConsistentIndentation')
    Rules        = $rules
}

Actual Output:

function verb-noun {
    <#
        .SYNOPSIS
        example

        .INPUTS
        String
        System.Management.Automation.PSCredential

        .OUTPUTS
        System.Management.Automation.PSCustomObject

        .NOTES

    #>
    [CmdLetBinding()]
    [OutputType([PSCustomObject])]
    Param(

        # Computer
        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String]
        $Computer,

        # Credential
        [Parameter(Mandatory = $true)]
        [System.Management.Automation.PSCredential]
        $Credential
    )

    $cmd = Get-ShowCommands | Where-Object { $_.Name -eq 'running-config' }
$result = Invoke-NetDeviceShowCommand -Computer $Computer -Credential $Credential -Command $cmd.CommandLine
Add-Member -InputObject $result -MemberType NoteProperty -Name "Name" -Value $cmd.Name
return $result
}

Notice $cmd = ... is indented differently to $result = ... onward.

I would expect $result = ... etc to indent as $cmd = ... has.

I'll let Eric Marquez (@ebmarquez) follow up.

Activity

  1. ebmarquez commented on May 13, 2019

    @ebmarquez

    Thanks Rob Holt (@rjmholt) for opening this in the correct repo. Psscriptanalyzer is not indening correct after the param block. I've tried to set if to the correct location and PsScriptAnalyzer moving the lies forward.

    >     $PSVersionTable
    
    Name                           Value
    ----                           -----
    PSVersion                      5.1.18362.1
    PSEdition                      Desktop
    PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
    BuildVersion                   10.0.18362.1
    CLRVersion                     4.0.30319.42000
    WSManStackVersion              3.0
    PSRemotingProtocolVersion      2.3
    SerializationVersion           1.1.0.1
    
    > Get-Module -Name PsScriptAnalyzer
    
    ModuleType Version    Name                                ExportedCommands
    ---------- -------    ----                                ----------------
    Script     1.18.0     PSScriptAnalyzer                    {Get-ScriptAnalyzerRule, Invoke-Formatter, Invoke-ScriptAnalyzer}
    

    Example of syntax before: Test.psm1

    function Test-Config {
        <#
            .SYNOPSIS
            Get test-Config
    
            .INPUTS
            String
            System.Management.Automation.PSCredential
    
            .OUTPUTS
            System.Management.Automation.PSCustomObject
    
            .NOTES
    
        #>
        [CmdLetBinding()]
        [OutputType([PSCustomObject])]
        Param(
    
            # Computer
            [Parameter(Mandatory = $true)]
            [ValidateNotNullOrEmpty()]
            [String]
            $Computer,
    
            # Credential
            [Parameter(Mandatory = $true)]
            [System.Management.Automation.PSCredential]
            $Credential
        )
    
        $cmd = Get-Commands | Where-Object { $_.Name -eq 'running-config' }
        $result = Invoke-NetDeviceCommand -Computer $Computer -Credential $Credential -Command $cmd.CommandLine
        Add-Member -InputObject $result -MemberType NoteProperty -Name "Name" -Value $cmd.Name
        return $result
    }

    After PsScriptAnalizer formats the syntax.

        $rules = @{
    >>         PSUseConsistentIndentation = @{
    >>             Enable = $true
    >>             IndentationSize = 4
    >>             PipelineIndentation = 'IncreaseIndentationAfterEveryPipeline'
    >>             Kind = 'space'
    >>         }
    >>     }
    C:\Users\emarq> $scriptDefinition = Get-Content -Raw C:\Temp\Test.psm1
    C:\Users\emarq> Invoke-Formatter -ScriptDefinition $scriptDefinition -Settings @{
    >>     IncludeRules = @('PSUserConsistentIndentation')
    >>     Rules        = $rules
    >> }
    function Test-Config {
        <#
            .SYNOPSIS
            Get test-Config
    
            .INPUTS
            String
            System.Management.Automation.PSCredential
    
            .OUTPUTS
            System.Management.Automation.PSCustomObject
    
            .NOTES
    
        #>
        [CmdLetBinding()]
        [OutputType([PSCustomObject])]
        Param(
    
            # Computer
            [Parameter(Mandatory = $true)]
            [ValidateNotNullOrEmpty()]
            [String]
            $Computer,
    
            # Credential
            [Parameter(Mandatory = $true)]
            [System.Management.Automation.PSCredential]
            $Credential
        )
    
        $cmd = Get-Commands | Where-Object { $_.Name -eq 'running-config' }
    $result = Invoke-NetDeviceCommand -Computer $Computer -Credential $Credential -Command $cmd.CommandLine
    Add-Member -InputObject $result -MemberType NoteProperty -Name "Name" -Value $cmd.Name
    return $result
    }
    
  2. msftrncs commented on May 17, 2019

    @msftrncs

    I think this is similar to #1236, if you turn off the indention for pipe's, it will format this correctly.

  3. johlju commented on Jun 7, 2019

    @johlju
    Contributor

    Saw this problem using IncreaseIndentationAfterEveryPipeline. It will also format correctly if writing the code correctly.
    I think the problem is that it should first add a new line after each | before formatting. See next comment.

    Assume this code.

    if ($true)
    {
        Get-ChildItem | Get-Content
    
        return
    }

    This fails when formatting.

    if ($true)
    {
        Get-ChildItem | Get-Content
    
    return
    }

    Assume this code

    if ($true)
    {
        Get-ChildItem |
        Get-Content
    
        return
    }

    Formats correctly.

    if ($true)
    {
        Get-ChildItem |
            Get-Content
    
        return
    }
  4. johlju commented on Jun 7, 2019

    @johlju
    Contributor

    I think the best solution is if the pipe is followed by something then do not format the pipe.

    For Pester tests this would be better too.

    Assume this code.

    It 'My test' {
        $myValue1 | Should -Be 1
        $myValue2 | Should -Be 2
    
        Assert-MockCalled -CommandName Get-Content -Exactly -Times 1 -Scope It
    }

    That would end up (if the formatting would work) as

    It 'My test' {
        $myValue1 | 
            Should -Be 1
        $myValue2 | 
            Should -Be 2
    
        Assert-MockCalled -CommandName Get-Content -Exactly -Times 1 -Scope It
    }

    Might not be the preference for tests. So if the user want to have that formatting then the user self must add row breaks after the first pipe.

  5. msftrncs commented on Jun 14, 2019

    @msftrncs

    The example from Rob Holt (@rjmholt) seems to format correctly now with 1.18.1.

  6. johlju commented on Jun 17, 2019

    @johlju
    Contributor

    Yes, I would say this issue is resolved. To get the indentation the user must self move the right part to the next line, as per my previous comment. I'm happy with this.

  7. bergmeister commented on Jun 18, 2019

    @bergmeister
    Collaborator

    Yes, I tested all examples and they are all resolved in 1.18.1. The fix for it was in PR #1191.
    Note that even with the fixes in 1.18.1, people found another edge case, PR 1261 is open for that already.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions