Skip to content

Extend CheckTokenTypeCasing to enforce lowercase Type token casing #2572

Description

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

  • CheckTokenTypeCasing's ValidateSet includes "Type".
  • Invoke-CodeFormatterOnFiles invokes the check with -Type Type.
  • Running the formatter against the reproducer (a script containing [DateTime], [TimeSpan], [Math]) reports errors without -Save and rewrites them to lowercase with -Save.
  • Fully-qualified type names ([System.Collections.Generic.List[object]], [System.StringComparer]) are left untouched.
  • A follow-up sweep PR normalizes existing offenders under Transport/, Shared/, Diagnostics/, etc.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Build ProcessLabel for build and release pipeline related itemsEnhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions