PSScriptAnalyzer icon indicating copy to clipboard operation
PSScriptAnalyzer copied to clipboard

variable assignments are not aligned

Open xhzkp opened this issue 4 months ago • 3 comments

After executing the following code, the = in variable assignments are not aligned, and the = in the first hashtable are also not aligned. I tested this in PowerShell 5.1 on Windows 10.

cls
$s = @'
$hashtable = @{ property1    ="value"
    anotherProperty= "another value"
}
$hashtable = @{
    property1 = "value"
    anotherProperty = "another value"
}
$hashtable = @{
    property1              = "value"
    anotherProperty = "another value"
}
$a= "hello"
   $ccc = "world"
 $b="Hi"
function foo {
"hello"
}
'@
$settings = @{
    IncludeRules = @("PSPlaceOpenBrace", "PSUseConsistentIndentation", "PSUseConsistentWhitespace","PSAlignAssignmentStatement")
    Rules = @{
        PSPlaceOpenBrace = @{
            Enable = $true
            OnSameLine = $false
        }
        PSUseConsistentIndentation = @{
        Enable = $true
			Kind = 'tab' # space,tab
			IndentationSize = 1
			PipelineIndentation = 'NoIndentation'
        }
        PSAlignAssignmentStatement = @{
            Enable = $true
            CheckHashtable = $true
        }
    }
}
Invoke-Formatter -ScriptDefinition $s -Settings $settings

xhzkp avatar Aug 27 '25 04:08 xhzkp

There's no rule for this in PowerShell Script Analyzer as of now. As you've already worked out, the PSAlignAssignmentStatement rule acts only on key/value pairs in a hashtable (or DSC Config) - not on blocks of assignment statements.

There's already an issue, marked Up-for-Grabs about exactly this. #1029 There's a corresponding issue about enum type alignment also. #1860

liamjpeters avatar Aug 27 '25 16:08 liamjpeters

@liamjpeters Vertical alignment is important for improving code readability. Is it possible to add this option?

Additionally, the = signs in the first hash table in the example code above are not aligned, which seems to be a bug.

xhzkp avatar Aug 27 '25 22:08 xhzkp

👋 Hey @xhzkp,

To address both your points:

Hashtable Alignment

The PSAlignAssignmentStatement rule isn't expecting you to have one key-value pair on the same line as the opening brace @{ and others on their own lines. The PSUseConsistentIndentation rule is also confused by this. If you disable PSUseConsistentIndentation, then PSAlignAssignmentStatement alignment works as well as it can in this non-standard situation.

This:

$hashtable = @{ property1    ="value"
    anotherProperty= "another value"
}

Becomes:

$hashtable = @{ property1 ="value"
    anotherProperty       = "another value"
}

The PSPlaceOpenBrace rule only operates on the braces of commands (scriptblocks, function bodies etc.)

Include variable assignments in Alignment rule

The project is always open to PRs, so if you wanted to tackle it, you are welcome to.

Adding in the alignment of variable assignments is not as straightforward as it may first seem. That's why #1029 has been open and Up-for-Grabs for over 7 years.

Some things to think about if you, or someone else in the future, would want to tackle it.

Which assignments to group?

hashtable's and enum's both encapsulate their key-value pair assignments. Everything within the object is lexically part of the same thing - so makes sense to share the same alignment.

Deciding on variable assignment groupings is much harder. How do you know which variables relate to one another and so should share the same alignment?

Two options could be:

  • Global: You inspect all assignments. You work out the largest LHS and use that to align all assignments in that scope. You do the same thing for all nested scopes (scriptblocks/functions etc).

    This is the simplest but maybe the least desirable. A long variable name at the very start of your file would impact a short variable hundreds of lines below it (which likely relates to something totally different). This would look odd - I'm sure you'd agree.

  • Lexical Grouping: You look for groups of assignment which are, perhaps, on consecutive lines. You treat them as related and align their equals signs vertically.

    • What about comment lines? Do they separate one group of variables from another or are they ignored?

    • What about when one line has many assignments? i.e. $a = 'foo';$b = 'bar'; $c = 'baz'?

    • What about lines with chain assignments? i.e. $a = $b = 1?

    • What about assignments where the RHS spans multiple lines? i.e.

      $processName = 'Code'
      $process = Get-Process |
            Where-Object {$_.name -eq $ProcessName} |
            Select-Object -First 1
      # Get the Window title for logging
      $MainWindowTitle = $process.MainWindowTitle
      
    • What about where indentation doesn't match from one line to the next? (There's other rules that handle this in PSSA, but this rule needs to act independently).

What is an assignment anyway?

Which assignment types do you pick to align?

  • Do we only align typical variable assignments? i.e. $a = 'foo'

  • Do we align property assignments? i.e. $a.bar = 'baz'

  • Do we align array assignments? $a[0] = 'foo'?

  • What about the short-hand assignments such as: $a += 5, $a -= 10, $a *= 5, $a /= 10?

  • How do we treat line the continuation characters - backtick (`)

Lots to consider.

liamjpeters avatar Aug 28 '25 15:08 liamjpeters