Skip to content

Add a formatter check to disallow backtick line continuation #2573

Description

Summary

Our code formatter (.build/Invoke-CodeFormatterOnFiles.ps1) has no check that flags backtick (`) line continuation in .ps1 / .psm1 files. Backtick continuation is a well-known PowerShell anti-pattern — trailing whitespace after the backtick silently breaks the continuation, and the character is easy to miss in review. Splatting, breaking after a pipe (|), or breaking inside an open paren / brace is preferred in every case.

Neither PSSA (as configured in PSScriptAnalyzerSettings.psd1) nor any of the existing CodeFormatterChecks/ files (CheckContainsCurlyQuotes, CheckFileHasNewlineAtEndOfFile, CheckMarkdownFileHasNoBOM, CheckMultipleEmptyLines, CheckScriptFileHasBOM, CheckScriptFileHasComplianceHeader, CheckScriptFormat, CheckTokenTypeCasing) target backtick continuation. PSAvoidUsingBackticks is not a built-in PSSA rule (it lives in the community CommunityAnalyzerRules module) and is not referenced anywhere in this repo.

Evidence

Discovered while reviewing PR #2571.

  • Transport/Get-TerrlExternalRecipientEstimate.ps19 backtick continuations (lines 316–319, 830–833, 879).
  • Transport/Tests/Get-TerrlExternalRecipientEstimate.Tests.ps139 backtick continuations.

Every occurrence in the PR is either a cmdlet call that would be more readable as a splat, or an expression that could break naturally after | / (. Example:

# Before (line 316)
} elseif (Test-TerrlExchangeOnlineJournalReport `
        -SenderAddress $senderAddress `
        -Recipient $recipient `
        -JournalSet $journalSet `
        -JournalSenderSet $journalSenderSet) {

# After (splat)
$journalArgs = @{
    SenderAddress    = $senderAddress
    Recipient        = $recipient
    JournalSet       = $journalSet
    JournalSenderSet = $journalSenderSet
}
} elseif (Test-TerrlExchangeOnlineJournalReport @journalArgs) {

Proposed change

Add a new CheckBacktickLineContinuation.ps1 under .build/CodeFormatterChecks/ and wire it into .build/Invoke-CodeFormatterOnFiles.ps1:

$errorCount += (CheckBacktickLineContinuation $fileInfo $Save) ? 1 : 0

Detection strategy: tokenize with [System.Management.Automation.PSParser]::Tokenize (already used by CheckTokenTypeCasing) and flag any LineContinuation token, OR match the regex `\s*$ on non-blank source lines that are outside here-strings, comments, and string literals (token stream is safer than the regex — regex would produce false positives inside single-line here-strings or ` characters inside strings).

Reporting: each occurrence should be reported with file + 1-based line number so contributors can locate them quickly.

-Save behavior: none. Auto-fixing backticks to splats is not safe (requires choosing splat variable names, deciding on placement), so this check should be report-only and let the author refactor by hand.

Acceptance criteria

  • CheckBacktickLineContinuation.ps1 exists and is dot-sourced by Invoke-CodeFormatterOnFiles.ps1.
  • Invoke-CodeFormatterOnFiles calls it for each file and increments $errorCount on hits.
  • Running against a repro script containing a backtick continuation returns a non-zero error count and prints file + line number.
  • Backticks inside strings, here-strings (@" ... "@, @' ... '@), and comments do not trigger the check.
  • Escaped characters that legitimately use backticks in strings ("`t", "`n", "`$var") are not flagged.
  • -Save is a no-op for this check (auto-rewrite is not attempted).
  • A follow-up sweep PR (or PRs, if scope requires) removes existing offenders across Admin/, Diagnostics/, Shared/, Transport/, Setup/, and the Tests/ folders.

Non-goals

  • Auto-fix. Refactoring backtick continuations into splats or natural pipe/paren breaks is an authoring decision, not a formatter transformation.
  • Blocking backticks in interactive PowerShell examples inside docs/ markdown files.
  • Adding the CommunityAnalyzerRules module as a formatter dependency.

Repro

@'
Get-ChildItem -Path C:\Temp `
    -Recurse `
    -Filter *.log
'@ | Set-Content -Path .\repro.ps1 -Encoding utf8BOM

. .build\Invoke-CodeFormatterOnFiles.ps1
Invoke-CodeFormatterOnFiles -FilePaths .\repro.ps1  # currently returns 0 errors

Related

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