Closed nixuno closed 4 months ago
Thanks @nixuno we were able to reproduce this
This is quite an interesting one 😀. A slightly simplified repro in PSScriptAnalyzer is:
Invoke-Formatter -ScriptDefinition 'Invoke-Foo 3>&1 1>&1 2>&1' -Settings @{
Rules = @{
PSUseConsistentWhitespace = @{
Enable = $true
CheckParameter = $true
}
}
}
Results in:
Invoke-Foo 1>&1
The PSUseConsistentWhitespace
rule, when CheckParameter
is true
, is looking over all the CommandAst
nodes.
For each CommandAst
, it's finding all the direct children of the current CommandAst
node.
It's checking then that each one sequentially is separated by a 1 character gap.
It seems to be making the implicit assumption that the direct children of the CommandAst
are read from the AST in token order. This is, apparently, not the case.
Looking at the AST of our example Invoke-Foo 3>&1 1>&1 2>&1
:
ScriptBlockAst [0,25)
└ NamedBlockAst [0,25)
└ PipelineAst [0,25)
└ CommandAst [0,25)
├ StringConstantExpression [0,10)
├ MergingRedirectionAst [16,20)
├ MergingRedirectionAst [21,25)
└ MergingRedirectionAst [11,15)
We see that evidentially, the MergingRedirectionAst
nodes are read from the tree in stream order (very interesting!).
Note the start of each
MergingRedirectionAst
nodes extent - the number after[
- is not in order down the list. The first node read from the tree is the second token,1>&1
, followed by the last token,2>&1
, and finally the first of the redirects in our input command,3>&1
.
I'm not smart enough to confirm this within the main Powershell Repo's parser - but I've tried with various orders of Invoke-Foo 3>&1 2>&1 1>&1 5>&1 4>&1 6>&1
and it appears to be consistent.
My unrefined naive solution would be to sort the command parameters (the direct children of the CommandAst
), first by their Extents StartLineNumber
, then by the StartColumnNumber
. Then proceed as planned.
This works as expected and our repro code correctly produces:
Invoke-Foo 3>&1 1>&1 2>&1
I would need to look at how badly this sorting impacts performance and for any edge cases.
Prerequisites
Summary
When formatting the following PowerShell while
powershell.codeFormatting.whitespaceBetweenParameters = true
, it removes two of the redirectors:Pre-Format
Post-Format
I would expect the redirectors to be left alone.
PowerShell Version
Visual Studio Code Version
Extension Version
Steps to Reproduce
test.ps1
:Shift + Alt + F
to format the document.Visuals
No response
Logs
No response