Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The PSAvoidTrailingWhitespace rule is not applied when using Invoke-Formatter #1992

Open
Ju-l1a opened this issue Apr 9, 2024 · 6 comments · May be fixed by #1993
Open

The PSAvoidTrailingWhitespace rule is not applied when using Invoke-Formatter #1992

Ju-l1a opened this issue Apr 9, 2024 · 6 comments · May be fixed by #1993

Comments

@Ju-l1a
Copy link

Ju-l1a commented Apr 9, 2024

Steps to reproduce

Using Invoke-Formatter does not apply the PSAvoidTrailingWhitespace rule as shown by the following example script:

$script = @"
Function Get-Example {   
    'Example'   
}   
"@

$settings = @{
	IncludeRules = @("PSAvoidTrailingWhitespace")
}

$formatted = Invoke-Formatter -ScriptDefinition $script -Settings $settings

Out-File -FilePath ./result.ps1 -InputObject $formatted -Encoding utf8 -NoNewline

Invoke-ScriptAnalyzer -Path ./result.ps1

Expected behavior

# There should be no linting results after formatting

Actual behavior

# There are linting results even after formatting
RuleName                            Severity     ScriptName Line  Message
--------                            --------     ---------- ----  -------
PSAvoidTrailingWhitespace           Information  result.ps1 1     Line has trailing whitespace
PSAvoidTrailingWhitespace           Information  result.ps1 2     Line has trailing whitespace
PSAvoidTrailingWhitespace           Information  result.ps1 3     Line has trailing whitespace

Environment data

> $PSVersionTable
Name                           Value
----                           -----
PSVersion                      5.1.22621.2506
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.22621.2506
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1

> (Get-Module -ListAvailable PSScriptAnalyzer).Version | ForEach-Object { $_.ToString() }
1.22.0
@Ju-l1a
Copy link
Author

Ju-l1a commented Apr 9, 2024

This is possibly a duplicate of #1757

@bergmeister
Copy link
Collaborator

bergmeister commented Apr 9, 2024

Invoke-Formatter has a hard-coded list of 'allowed' rules that are defined here that PSAvoidTrailingWhitespace is not part of it but I think we could add it to enable your use case :-)

var ruleOrder = new string[]
{
"PSPlaceCloseBrace",
"PSPlaceOpenBrace",
"PSUseConsistentWhitespace",
"PSUseConsistentIndentation",
"PSAlignAssignmentStatement",
"PSUseCorrectCasing",
"PSAvoidUsingCmdletAliases",
"PSAvoidUsingDoubleQuotesForConstantString",
"PSAvoidSemicolonsAsLineTerminators",
"PSAvoidExclaimOperator",
};

@Ju-l1a
Copy link
Author

Ju-l1a commented Apr 9, 2024

Adding the rule to this list (and running build.ps1& importing the module) alone does not seem to change the behavior for me. Am I missing something?

@liamjpeters
Copy link
Contributor

It looks as though the formatter considers each of the rules in the ruleOrder array, so adding it is correct.

It does, however, skip over any rule that doesn't have (even empty) arguments passed in through settings. I'm not clear on the context of why this is done.

foreach (var rule in ruleOrder)
{
if (!settings.RuleArguments.ContainsKey(rule))
{
continue;
}

So for instance, once the rule is added as @bergmeister suggests:

$script = @"
Function Get-Example {   
    'Example'   
}   
"

$settings = @{
    Rules = @{
        PSAvoidTrailingWhitespace = @{}
    }
}

$formatted = Invoke-Formatter -ScriptDefinition $script -Settings $settings

Runs the rule and "fixes" it, but I get a "fixed" script that no longer includes the closing curly-brace.

Function Get-Example {
    'Example'
RuleName                            Severity     ScriptName Line  Message
--------                            --------     ---------- ----  -------
MissingEndCurlyBrace                ParseError              1     Missing closing '}' in statement block or type definition.

This looks to be the same issue described in #1757

@liamjpeters
Copy link
Contributor

liamjpeters commented Apr 9, 2024

Interestingly:

$script = @"
Function Get-Example {   
    'Example'   
 }   
"

$settings = @{
    Rules = @{
        PSAvoidTrailingWhitespace = @{}
    }
}

$formatted = Invoke-Formatter -ScriptDefinition $script -Settings $settings

Note the space before the closing curly-brace in $script

results in:

Function Get-Example {
    'Example'
 }

and

$script = @"
Function Get-Example {   
    'Example'   
 }   
Function Get-Example {   
    'Example'   
}   
Function Get-Example {   
    'Example'   
 }   
"@

$settings = @{
    Rules = @{
        PSAvoidTrailingWhitespace = @{}
    }
}

$formatted = Invoke-Formatter -ScriptDefinition $script -Settings $settings

results in:

Function Get-Example {
    'Example'
 }
Function Get-Example {
    'Example'

Function Get-Example {
    'Example'
 }

So it looks like PSAvoidTrailingWhitespace has an issue with lines which contain trailing whitespace, but are only a single non-whitespace character in length. e.g. } .

The start column of the violationExtent calculated for the last line (} ) looks to be 1:

image

It's worked out here.

int startColumnOfTrailingWhitespace = 1;
for (int i = line.Length - 2; i > 0; i--)
{
if (line[i] != ' ' && line[i] != '\t')
{
startColumnOfTrailingWhitespace = i + 2;
break;
}
}

It's looking backward through the line for a non-space, non-tab character, and if it's not finding it, it's assuming the whitespace starts at column 1 (assume columns are 1-indexed and not 0-indexed?).

It's only checking up to character 1 in the string (loop condition is i > 0) and so it's stopping short of finding the curly-brace character at line[0]. If it find that, it would correctly say that the whitespace starts at column 2 (again, assuming columns are 1-indexed).

I think this bug should be simply changing i > 0 to be i >= 0.

Indeed doing so, I get correct looking results and all tests still pass. Happy to PR this, unless you want to have a go @Ju-l1a

@Ju-l1a
Copy link
Author

Ju-l1a commented Apr 9, 2024

@liamjpeters I'd be grateful if you can do the PR so I can see how it's done properly :)

Thank you for your help!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants