Skip to content

PSUseConsistentIndentation.PipelineIndentation.None or 3 deletes commandlet name #1580

Description

When PSUseConsistentIndentation.PipelineIndentation is set to None or 3 it deletes where-object and foreach-object

Steps to reproduce

Sample input:

Get-ChildItem |
Where-Object Name -Like 'foo'

Get-ChildItem |
ForEach-Object Name

It happens using the format

foo |
bar

These formats work correctly

foo | bar

foo
| bar

Test cases

$script = @'
Get-ChildItem |
Where-Object Name -Like 'foo'

Get-ChildItem |
ForEach-Object Name
'@

$settings = @{
    IncludeRules = @('PSUseConsistentIndentation')
    Rules        = @{
        PSUseConsistentIndentation = @{
            Enable              = $true
            # Kind                = 'space'
            PipelineIndentation = 'None' # broke
            # IndentationSize     = 4
        }

    }
}
"

To reproduce: PipelineIndentation = None/3`n"
Invoke-Formatter -ScriptDefinition $script -Settings $settings

foreach ($mode in ('IncreaseIndentationAfterEveryPipeline', 'IncreaseIndentationForFirstPipeline', 'IncreaseIndentationAfterEveryPipeline', 'NoIndentation', 'None', ''))
{
    "`n`nMode: '$Mode'`n"
    $settings.Rules.PSUseConsistentIndentation.PipelineIndentation = $Mode
    Invoke-Formatter -ScriptDefinition $script -Settings $settings
}

Expected behavior

Results that contain Foreach-Object and Where-Object

Get-ChildItem |
    Where-Object Name -Like 'foo'

Get-ChildItem |
    ForEach-Object Name

Actual behavior

Get-ChildItem |
Name -Like 'foo'

Get-ChildItem |
Name

All enum types:

Mode: 'IncreaseIndentationAfterEveryPipeline'

Get-ChildItem |
    Where-Object Name -Like 'foo'

Get-ChildItem |
    ForEach-Object Name


Mode: 'IncreaseIndentationForFirstPipeline'

Get-ChildItem |
    Where-Object Name -Like 'foo'

Get-ChildItem |
    ForEach-Object Name


Mode: 'IncreaseIndentationAfterEveryPipeline'

Get-ChildItem |
    Where-Object Name -Like 'foo'

Get-ChildItem |
    ForEach-Object Name


Mode: 'NoIndentation'

Get-ChildItem |
Where-Object Name -Like 'foo'

Get-ChildItem |
ForEach-Object Name

Mode: 'None'

Get-ChildItem |
Name -Like 'foo'

Get-ChildItem |
Name


Mode: ''

Get-ChildItem |
    Where-Object Name -Like 'foo'

Get-ChildItem |
    ForEach-Object Name

Environment data

Occurs in normal powershell and vscode-powershell's integrated terminal

> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      7.0.3
PSEdition                      Core
GitCommitId                    7.0.3
OS                             Microsoft Windows 10.0.19041
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

> (Get-Module -ListAvailable PSScriptAnalyzer).Version | ForEach-Object { $_.ToString() }
1.19.1
1.19.1

The existing issues like #1168 deal with formatting, not mutating code

Activity

  1. andyleejordan commented on Nov 1, 2021

    @andyleejordan
    Member

    Jake Bolton (@ninmonkey) Can you confirm if this is still reproducing with v1.20.0?

  2. SydneyhSmith commented on Nov 4, 2021

    @SydneyhSmith
    Collaborator

    I was able to reproduce this on 1.20.0 with indentation style 'none'

  3. andyleejordan commented on Nov 4, 2021

    @andyleejordan
    Member

    Seems like something we should prioritize, being destructive as it is.

  4. ninmonkey commented on Nov 8, 2021

    @ninmonkey
    Author

    Jake Bolton (@ninmonkey) Can you confirm if this is still reproducing with v1.20.0?

    It appears to only be breaking when set to PipelineIndentation = 'None'

    Environment

    Module Version
    PSScriptAnalyzer 1.20.0
    PowerShellEditorServices 0.2.0
    Powershell 7.1.4
    EditorServicesCommandSuite 1.0.0
    PowerShellEditorServices.Commands 0.2.0

    Initial script

    Get-ChildItem |
    Where-Object Name -Like 'foo'
    
    Get-ChildItem |
    ForEach-Object Name

    Mode: IncreaseIndentationAfterEveryPipeline

    Get-ChildItem |
        Where-Object Name -Like 'foo'
    
    Get-ChildItem |
        ForEach-Object Name

    Mode: IncreaseIndentationForFirstPipeline

    Get-ChildItem |
        Where-Object Name -Like 'foo'
    
    Get-ChildItem |
        ForEach-Object Name

    Mode: IncreaseIndentationAfterEveryPipeline

    Get-ChildItem |
        Where-Object Name -Like 'foo'
    
    Get-ChildItem |
        ForEach-Object Name

    Mode: NoIndentation

    Get-ChildItem |
    Where-Object Name -Like 'foo'
    
    Get-ChildItem |
    ForEach-Object Name

    Mode: None

    Get-ChildItem |
    Name -Like 'foo'
    
    Get-ChildItem |
    Name

    Mode: ``

    Get-ChildItem |
        Where-Object Name -Like 'foo'
    
    Get-ChildItem |
        ForEach-Object Name
  5. ninmonkey commented on Nov 8, 2021

    @ninmonkey
    Author

    Write-Verbose "$functionName User did not specify Region, using default values $($Region -join ', ')."

    Does that still occur in 1.20 ? I am not getting that, at least with this config

    $settings = @{
        IncludeRules = @('PSUseConsistentIndentation')
        Rules        = @{
            PSUseConsistentIndentation = @{
                Enable              = $true
                # Kind                = 'space'
                PipelineIndentation = 'None' # broke
                # IndentationSize     = 4
            }
        }
    }
  6. bergmeister commented on Nov 8, 2021

    @bergmeister
    Collaborator

    Thanks for the updated repro info, I know there were a few cases with the formatter removing code in 1.19.0 that were fixed in 1.19.1 but it seems there is still one case outstanding (or re-introduced), I will take a look at it this week ✋. At least it's only for a non-default settings and the affected PipelineIndentationStyle.None option was also only introduced in 1.19.0.

  7. bergmeister commented on Nov 13, 2021

    @bergmeister
    Collaborator

    I had a first look at it today, I can confirm it's a bug of the UseConsistentIndentation rule and it happens because when it gets to Name, it thinks its the first token after newline. The reset of the newline therefore does not work correctly, which should happen at the previous cmdlet (i.e. Where-Object or ForEach-Object in your 2 examples). The reason for that is the following line that evaluates to true

    if (pipelineIndentationStyle == PipelineIndentationStyle.None && PreviousLineEndedWithPipe(tokens, tokenIndex, token))

    Below is a PR with a fix, it seems the existing test cases were too simple to not catch this scenario.

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

Metadata

Metadata

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions