Skip to content

Commit 8f933fa

Browse files
author
Kapil Borle
authored
Merge pull request #713 from PowerShell/kapilmb/newline-close-brace
Add new line after close brace
2 parents 853c3d8 + c26a08b commit 8f933fa

File tree

5 files changed

+148
-5
lines changed

5 files changed

+148
-5
lines changed

Engine/Generic/CorrectionExtent.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,21 @@ public CorrectionExtent(
128128

129129
}
130130

131+
public CorrectionExtent(
132+
IScriptExtent violationExtent,
133+
string replacementText,
134+
string filePath)
135+
: this(
136+
violationExtent.StartLineNumber,
137+
violationExtent.EndLineNumber,
138+
violationExtent.StartColumnNumber,
139+
violationExtent.EndColumnNumber,
140+
replacementText,
141+
filePath)
142+
{
143+
144+
}
145+
131146
private void ThrowIfInvalidArguments()
132147
{
133148
ThrowIfNull<string>(text, "text");

RuleDocumentation/PlaceCloseBrace.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Close brace placement should follow a consistent style. It should be on a new li
1313
Enable = $true
1414
NoEmptyLineBefore = $false
1515
IgnoreOneLineBlock = $true
16+
NewLineAfter = $true
1617
}
1718
}
1819
```
@@ -28,4 +29,7 @@ Create violation if there is an empty line before a close brace.
2829
#### IgnoreOneLineBlock: bool (Default value is `$true`)
2930
Indicates if close braces in a one line block should be ignored or not.
3031
E.g. $x = if ($true) { "blah" } else { "blah blah" }
31-
In the above example, if the property is set to true then the rule will not fire a violation.
32+
In the above example, if the property is set to true then the rule will not fire a violation.
33+
34+
#### NewLineAfter: bool (Default value is `$true`)
35+
Indicates if a new line should follow a close brace. If set to true a close brace should be followed by a new line.

Rules/PlaceCloseBrace.cs

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public class PlaceCloseBrace : ConfigurableRule
3131
/// <summary>
3232
/// Indicates if there should or should not be an empty line before a close brace.
3333
///
34-
/// Default value if false.
34+
/// Default value is false.
3535
/// </summary>
3636
[ConfigurableRuleProperty(defaultValue:false)]
3737
public bool NoEmptyLineBefore { get; protected set; }
@@ -42,11 +42,21 @@ public class PlaceCloseBrace : ConfigurableRule
4242
/// In the above example, if the property is set to true then the rule will
4343
/// not fire a violation.
4444
///
45-
/// Default value if true.
45+
/// Default value is true.
4646
/// </summary>
4747
[ConfigurableRuleProperty(defaultValue: true)]
4848
public bool IgnoreOneLineBlock { get; protected set; }
4949

50+
/// <summary>
51+
/// Indicates if a new line should follow a close brace.
52+
///
53+
/// If set to true a close brace should be followed by a new line.
54+
///
55+
/// Default value is true.
56+
/// </summary>
57+
[ConfigurableRuleProperty(defaultValue: true)]
58+
public bool NewLineAfter { get; protected set; }
59+
5060
private HashSet<Token> tokensToIgnore;
5161

5262
/// <summary>
@@ -121,6 +131,13 @@ public override IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string file
121131
GetViolationForBraceShouldNotFollowEmptyLine(tokens, k, openBracePos, fileName),
122132
ref diagnosticRecords);
123133
}
134+
135+
if (NewLineAfter)
136+
{
137+
AddToDiagnosticRecords(
138+
GetViolationForBraceShouldHaveNewLineAfter(tokens, k, openBracePos, fileName),
139+
ref diagnosticRecords);
140+
}
124141
}
125142
else
126143
{
@@ -244,6 +261,22 @@ private List<CorrectionExtent> GetCorrectionsForBraceShouldNotFollowEmptyLine(
244261
return corrections;
245262
}
246263

264+
private List<CorrectionExtent> GetCorrectionsForBraceShouldHaveNewLineAfter(
265+
Token[] tokens,
266+
int closeBracePos,
267+
int openBracePos,
268+
string fileName)
269+
{
270+
var corrections = new List<CorrectionExtent>();
271+
var nextToken = tokens[closeBracePos + 1];
272+
var closeBraceToken = tokens[closeBracePos];
273+
corrections.Add(new CorrectionExtent(
274+
closeBraceToken.Extent,
275+
closeBraceToken.Text + Environment.NewLine,
276+
fileName));
277+
return corrections;
278+
}
279+
247280
private string GetIndentation(Token[] tokens, int closeBracePos, int openBracePos)
248281
{
249282
// if open brace on a new line by itself, use its indentation
@@ -271,7 +304,40 @@ private string GetIndentation(Token[] tokens, int closeBracePos, int openBracePo
271304
return new String(' ', firstTokenOnOpenBraceLine.Extent.StartColumnNumber - 1);
272305
}
273306

274-
private DiagnosticRecord GetViolationForBraceShouldBeOnNewLine(Token[] tokens, int closeBracePos, int openBracePos, string fileName)
307+
private DiagnosticRecord GetViolationForBraceShouldHaveNewLineAfter(
308+
Token[] tokens,
309+
int closeBracePos,
310+
int openBracePos,
311+
string fileName)
312+
{
313+
var expectedNewLinePos = closeBracePos + 1;
314+
if (tokens.Length > 1 && tokens.Length > expectedNewLinePos)
315+
{
316+
var closeBraceToken = tokens[closeBracePos];
317+
if (tokens[expectedNewLinePos].Kind != TokenKind.NewLine
318+
&& tokens[expectedNewLinePos].Kind != TokenKind.Comment
319+
&& !tokensToIgnore.Contains(tokens[closeBracePos]))
320+
{
321+
322+
return new DiagnosticRecord(
323+
GetError(Strings.PlaceCloseBraceErrorShouldFollowNewLine),
324+
closeBraceToken.Extent,
325+
GetName(),
326+
GetDiagnosticSeverity(),
327+
fileName,
328+
null,
329+
GetCorrectionsForBraceShouldHaveNewLineAfter(tokens, closeBracePos, openBracePos, fileName));
330+
}
331+
}
332+
333+
return null;
334+
}
335+
336+
private DiagnosticRecord GetViolationForBraceShouldBeOnNewLine(
337+
Token[] tokens,
338+
int closeBracePos,
339+
int openBracePos,
340+
string fileName)
275341
{
276342
if (tokens.Length > 1 && tokens.Length > closeBracePos)
277343
{

Rules/Strings.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -903,6 +903,9 @@
903903
<data name="PlaceCloseBraceErrorShouldNotFollowEmptyLine" xml:space="preserve">
904904
<value>Close brace does not follow a non-empty line.</value>
905905
</data>
906+
<data name="PlaceCloseBraceErrorShouldFollowNewLine" xml:space="preserve">
907+
<value>Close brace does not follow a new line.</value>
908+
</data>
906909
<data name="UseConsistentIndentationName" xml:space="preserve">
907910
<value>UseConsistentIndentation</value>
908911
</data>

Tests/Rules/PlaceCloseBrace.tests.ps1

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
1-
Import-Module PSScriptAnalyzer
1+
$directory = Split-Path -Parent $MyInvocation.MyCommand.Path
2+
$testRootDirectory = Split-Path -Parent $directory
3+
4+
Import-Module PSScriptAnalyzer
5+
Import-Module (Join-Path $testRootDirectory "PSScriptAnalyzerTestHelper.psm1")
6+
27
$ruleConfiguration = @{
38
Enable = $true
49
NoEmptyLineBefore = $true
510
IgnoreOneLineBlock = $true
11+
NewLineAfter = $true
612
}
713

814
$settings = @{
@@ -19,6 +25,9 @@ Describe "PlaceCloseBrace" {
1925
function foo {
2026
Write-Output "close brace not on a new line"}
2127
'@
28+
$ruleConfiguration.'NoEmptyLineBefore' = $false
29+
$ruleConfiguration.'IgnoreOneLineBlock' = $false
30+
$ruleConfiguration.'NewLineAfter' = $false
2231
$violations = Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings
2332
}
2433

@@ -39,6 +48,9 @@ function foo {
3948
4049
}
4150
'@
51+
$ruleConfiguration.'NoEmptyLineBefore' = $true
52+
$ruleConfiguration.'IgnoreOneLineBlock' = $false
53+
$ruleConfiguration.'NewLineAfter' = $false
4254
$violations = Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings
4355
}
4456

@@ -56,6 +68,9 @@ function foo {
5668
$def = @'
5769
$hashtable = @{a = 1; b = 2}
5870
'@
71+
$ruleConfiguration.'NoEmptyLineBefore' = $false
72+
$ruleConfiguration.'IgnoreOneLineBlock' = $true
73+
$ruleConfiguration.'NewLineAfter' = $false
5974
$violations = Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings
6075
}
6176

@@ -71,6 +86,9 @@ $hashtable = @{
7186
a = 1
7287
b = 2}
7388
'@
89+
$ruleConfiguration.'NoEmptyLineBefore' = $false
90+
$ruleConfiguration.'IgnoreOneLineBlock' = $true
91+
$ruleConfiguration.'NewLineAfter' = $false
7492
$violations = Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings
7593
}
7694

@@ -101,4 +119,41 @@ $x = if ($true) { "blah" } else { "blah blah" }
101119
$violations.Count | Should Be 0
102120
}
103121
}
122+
123+
Context "When a close brace should be follow a new line" {
124+
BeforeAll {
125+
$def = @'
126+
if (Test-Path "blah") {
127+
"blah"
128+
} else {
129+
"blah blah"
130+
}
131+
'@
132+
$ruleConfiguration.'NoEmptyLineBefore' = $false
133+
$ruleConfiguration.'IgnoreOneLineBlock' = $false
134+
$ruleConfiguration.'NewLineAfter' = $true
135+
$violations = Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings
136+
}
137+
138+
It "Should find two violations" {
139+
$violations.Count | Should Be 2
140+
$params = @{
141+
RawContent = $def
142+
DiagnosticRecord = $violations[0]
143+
CorrectionsCount = 1
144+
ViolationText = '}'
145+
CorrectionText = '}' + [System.Environment]::NewLine
146+
}
147+
Test-CorrectionExtentFromContent @params
148+
149+
$params = @{
150+
RawContent = $def
151+
DiagnosticRecord = $violations[1]
152+
CorrectionsCount = 1
153+
ViolationText = '}'
154+
CorrectionText = '}' + [System.Environment]::NewLine
155+
}
156+
Test-CorrectionExtentFromContent @params
157+
}
158+
}
104159
}

0 commit comments

Comments
 (0)