Summary
Our code formatter's CheckTokenTypeCasing check (.build/CodeFormatterChecks/CheckTokenTypeCasing.ps1) currently only inspects Operator and Keyword PowerShell token types. It does not inspect the Type token type, which means inconsistent casing of type accelerators and built-in .NET short-form names slips through the pipeline unnoticed.
Neither PSSA's PSUseCorrectCasing (as configured in PSScriptAnalyzerSettings.psd1) nor any of the other seven checks wired into Invoke-CodeFormatterOnFiles flag this either — verified by running the current settings against a file mixing [DateTime]/[datetime], [TimeSpan], [Math]/[math] (zero diagnostics).
Evidence
Discovered while reviewing PR #2571. Transport/Get-TerrlExternalRecipientEstimate.ps1 uses both spellings in the same 911-line file, and the same concept is spelled two different ways:
| Lowercase (majority) |
PascalCase (nested wrapper) |
L100, L103, L449, L450, L497 [datetime] |
L539, L542 [DateTime] |
L387, L401 [math] |
L588 [Math] |
| — |
L532 [TimeSpan], L533/L579/L595/L602 [DateTime], L453 [ScriptBlock] |
The formatter, SpellCheck.ps1, and Pester all pass, so the mixed casing merges cleanly.
Proposed change
Extend CheckTokenTypeCasing.ps1 to accept Type as a third option in the -Type ValidateSet, then wire a new call into .build/Invoke-CodeFormatterOnFiles.ps1:
$errorCount += (CheckTokenTypeCasing $fileInfo $Save "Type") ? 1 : 0
Enforcement rule: for tokens with PSTokenType.Type whose Content matches a known type accelerator or built-in short type name (datetime, timespan, string, int, bool, guid, math, scriptblock, hashtable, pscustomobject, object, convert, char, byte, long, double, decimal, regex, xml, array, void, type, etc.), require the lowercase form. Fully-qualified .NET namespaces ([System.DateTime], [System.Collections.Generic.List[object]]) should be left alone — those retain their canonical framework casing.
-Save behavior: rewrite the token in place using the same offset/insert pattern the existing Operator/Keyword branches already use.
Acceptance criteria
Non-goals
- Enforcing casing on fully-qualified .NET type names (that's already handled correctly by the framework and would produce large, noisy diffs).
- Any change to
PSScriptAnalyzerSettings.psd1.
Repro
@'
[DateTime]::UtcNow
[TimeSpan]::FromMinutes(5)
[Math]::Round(1.0, 1)
'@ | Set-Content -Path .\repro.ps1 -Encoding utf8BOM
. .build\Invoke-CodeFormatterOnFiles.ps1
Invoke-CodeFormatterOnFiles -FilePaths .\repro.ps1 # currently returns 0 errors
Summary
Our code formatter's
CheckTokenTypeCasingcheck (.build/CodeFormatterChecks/CheckTokenTypeCasing.ps1) currently only inspectsOperatorandKeywordPowerShell token types. It does not inspect theTypetoken type, which means inconsistent casing of type accelerators and built-in .NET short-form names slips through the pipeline unnoticed.Neither PSSA's
PSUseCorrectCasing(as configured inPSScriptAnalyzerSettings.psd1) nor any of the other seven checks wired intoInvoke-CodeFormatterOnFilesflag this either — verified by running the current settings against a file mixing[DateTime]/[datetime],[TimeSpan],[Math]/[math](zero diagnostics).Evidence
Discovered while reviewing PR #2571.
Transport/Get-TerrlExternalRecipientEstimate.ps1uses both spellings in the same 911-line file, and the same concept is spelled two different ways:[datetime][DateTime][math][Math][TimeSpan], L533/L579/L595/L602[DateTime], L453[ScriptBlock]The formatter,
SpellCheck.ps1, and Pester all pass, so the mixed casing merges cleanly.Proposed change
Extend
CheckTokenTypeCasing.ps1to acceptTypeas a third option in the-TypeValidateSet, then wire a new call into.build/Invoke-CodeFormatterOnFiles.ps1:Enforcement rule: for tokens with
PSTokenType.TypewhoseContentmatches a known type accelerator or built-in short type name (datetime,timespan,string,int,bool,guid,math,scriptblock,hashtable,pscustomobject,object,convert,char,byte,long,double,decimal,regex,xml,array,void,type, etc.), require the lowercase form. Fully-qualified .NET namespaces ([System.DateTime],[System.Collections.Generic.List[object]]) should be left alone — those retain their canonical framework casing.-Savebehavior: rewrite the token in place using the same offset/insert pattern the existingOperator/Keywordbranches already use.Acceptance criteria
CheckTokenTypeCasing'sValidateSetincludes"Type".Invoke-CodeFormatterOnFilesinvokes the check with-Type Type.[DateTime],[TimeSpan],[Math]) reports errors without-Saveand rewrites them to lowercase with-Save.[System.Collections.Generic.List[object]],[System.StringComparer]) are left untouched.Transport/,Shared/,Diagnostics/, etc.Non-goals
PSScriptAnalyzerSettings.psd1.Repro