PowerShell / PowerShell/PSScriptAnalyzer
PSUseConsistentIndentation double-indents attribute bodies that open a scriptblock (`[Attr({ … })]`)
还没有人认领这个 Issue。
- 主要语言
- C#
- 星标
- 2.2k
- 派生
- 414
- 平均合并
- 13 小时 1 分钟
- 30 天内合并 PR
- 2
描述
Prerequisites
- I have read the documentation and my issue is not covered there.
- I have searched the existing issues and my issue is not already reported.
Summary
PSUseConsistentIndentation (and therefore Invoke-Formatter) double-indents the body of an attribute that opens a scriptblock, e.g. [ArgumentCompleter({...})]. The body gets IndentationSize * 2 and the closing })] gets IndentationSize * 1.
This looks like the same root cause as #2159 (hashtable inside a method call: the LParen and the AtCurly each add an indentation level). Here the two adjacent openers are ( and { from a type/attribute literal instead of @{, so [AttributeName({ hits it too. #2159 was fixed on main by #2173 ("only the last unclosed opener on a line affects indentation"), but neither that fix nor #2159 covers the attribute form, and it is still broken in the latest release 1.25.0.
Steps to reproduce
$code = @'
[ArgumentCompleter({
Param($commandName, $parameterName)
$validKeys = @('a', 'b')
$validKeys | Where-Object { $_ } | ForEach-Object { "$_=" }
})]
'@
$settings = @{
IncludeRules = @('PSUseConsistentIndentation')
Rules = @{
PSUseConsistentIndentation = @{
Enable = $true
IndentationSize = 4
Kind = 'tab'
}
}
}
Invoke-Formatter -ScriptDefinition $code -Settings $settings
Expected behavior
One level of indentation for the body, matching the opener line, and the closing })] at the opener's level:
[ArgumentCompleter({
Param($commandName, $parameterName)
$validKeys = @('a', 'b')
$validKeys | Where-Object { $_ } | ForEach-Object { "$_=" }
})]
Actual behavior
Two levels for the body and one level for the closing })]:
[ArgumentCompleter({
Param($commandName, $parameterName)
$validKeys = @('a', 'b')
$validKeys | Where-Object { $_ } | ForEach-Object { "$_=" }
})]
The same happens with spaces (Kind = 'space', IndentationSize = 4) and with NewLineAfterOpenBrace/PSPlaceOpenBrace not involved at all — PSUseConsistentIndentation alone is enough.
It also affects other attribute forms that open a scriptblock, e.g.
[ValidateScript({
$_ -gt 0
})]
and the buggy output is not idempotent in a harmless way: because the opener line itself is not re-indented, re-running the formatter keeps the body at the wrong level, and any tool that re-applies formatting sees a permanent diff.
Environment
PSVersion: 7.6.6
PSEdition: Core
OS: Windows 11 (26100)
PSScriptAnalyzer: 1.25.0
Also reproduced with PSScriptAnalyzer 1.24.0 (bundled with ms-vscode.powershell 2025.4.0) and with Windows PowerShell 5.1 / 26100 (Desktop edition), so it is not host- or edition-specific.
Related
- #2159 —
PSUseConsistentIndentation: Hashtable inside method call gets double-indented (sameLParen+XCurlydouble count; fixed by #2173) - #2173 — the fix that pops the level when an opener is not the last unclosed opener on the line; it does not catch the attribute opening
({ - #1168 — "Formatting
.whereand.foreachmethods is incorrect" (adjacent-opener family)
贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
调研方向
首先运行提供的 Invoke-Formatter 重现,并启用 PSUseConsistentIndentation,然后跟踪当属性或类型字面量打开 scriptblock 时 PSUseConsistentIndentation 规则的缩进处理。添加一个涵盖 [ArgumentCompleter({ ... })] 和 [ValidateScript({ ... })] 的回归测试,验证正文有一个缩进级别,并且闭合 })] 位于打开位置的级别。
由索引模型根据 Issue 内容生成。
评估
- 技术栈
- csharp, powershell
- 领域
- tooling
- Issue 类型
- 缺陷
- 难度
- 3/5
- 预计耗时
- 1-2 天
- 活跃度
- 活跃
- 描述清晰度
- 描述清楚
- 新手友好度
- 70/100