Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
ninmonkey opened this issue Aug 31, 2020 · 8 comments · Fixed by #1746
Closed

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

ninmonkey opened this issue Aug 31, 2020 · 8 comments · Fixed by #1746

Comments

@ninmonkey
Copy link

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

@ghost
Copy link

ghost commented Feb 1, 2021

another way this seems to occur (related to my submission #2962), is strings with command substitution are also affected when applying formatting. for example, original code:

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

becomes

Write-Verbose "$functionName $($Region ', ')."

after applying document formatting.

request: would it be possible or even be practical to add an option to ignore string contents when applying document formatting? @SydneyhSmith

@andyleejordan
Copy link
Member

@ninmonkey Can you confirm if this is still reproducing with v1.20.0?

@SydneyhSmith
Copy link
Collaborator

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

@andyleejordan
Copy link
Member

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

@andyleejordan andyleejordan self-assigned this Nov 4, 2021
@ninmonkey
Copy link
Author

@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

@ninmonkey
Copy link
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
        }
    }
}

@bergmeister bergmeister self-assigned this Nov 8, 2021
@bergmeister
Copy link
Collaborator

bergmeister commented Nov 8, 2021

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.

@bergmeister
Copy link
Collaborator

bergmeister commented Nov 13, 2021

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