Skip to content

Commit acd9976

Browse files
committed
Fix #96 move using statements even if there are parse errors afteward
Merge pull request #97 from gaelcolas/fix/#96 +semver:fix
2 parents 5a3f1b8 + 6ffc477 commit acd9976

File tree

8 files changed

+85
-105
lines changed

8 files changed

+85
-105
lines changed

Source/Private/CopyReadMe.ps1

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,21 +21,22 @@ function CopyReadMe {
2121
# If set, overwrite the existing readme
2222
[Switch]$Force
2323
)
24+
process {
25+
# Copy the readme file as an about_ help file
26+
Write-Verbose "Test for ReadMe: $Pwd\$($ReadMe)"
27+
if ($ReadMe -and (Test-Path $ReadMe -PathType Leaf)) {
28+
# Make sure there's a language path
29+
$LanguagePath = Join-Path $OutputDirectory $Culture
30+
if (!(Test-Path $LanguagePath -PathType Container)) {
31+
$null = New-Item $LanguagePath -Type Directory -Force
32+
}
33+
Write-Verbose "Copy ReadMe to: $LanguagePath"
2434

25-
# Copy the readme file as an about_ help file
26-
Write-Verbose "Test for ReadMe: $Pwd\$($ReadMe)"
27-
if($ReadMe -and (Test-Path $ReadMe -PathType Leaf)) {
28-
# Make sure there's a language path
29-
$LanguagePath = Join-Path $OutputDirectory $Culture
30-
if(!(Test-Path $LanguagePath -PathType Container)) {
31-
$null = New-Item $LanguagePath -Type Directory -Force
32-
}
33-
Write-Verbose "Copy ReadMe to: $LanguagePath"
34-
35-
$about_module = Join-Path $LanguagePath "about_$($ModuleName).help.txt"
36-
if(!(Test-Path $about_module)) {
37-
Write-Verbose "Turn readme into about_module"
38-
Copy-Item -LiteralPath $ReadMe -Destination $about_module
35+
$about_module = Join-Path $LanguagePath "about_$($ModuleName).help.txt"
36+
if (!(Test-Path $about_module)) {
37+
Write-Verbose "Turn readme into about_module"
38+
Copy-Item -LiteralPath $ReadMe -Destination $about_module -Force:$Force
39+
}
3940
}
4041
}
4142
}

Source/Private/GetBuildInfo.ps1

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ function GetBuildInfo {
22
[CmdletBinding()]
33
param(
44
# The path to the Build Manifest Build.psd1
5-
[Parameter()][AllowNull()]
5+
[Parameter()]
6+
[AllowNull()]
67
[string]$BuildManifest,
78

89
# Pass MyInvocation from the Build-Command so we can read parameter values

Source/Private/MoveUsingStatements.ps1

Lines changed: 46 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ function MoveUsingStatements {
1616
those changes won't be applied to the file.
1717
#>
1818
[CmdletBinding()]
19-
Param(
19+
param(
2020
# Path to the PSM1 file to amend
2121
[Parameter(Mandatory, ValueFromPipelineByPropertyName, ValueFromPipeline)]
2222
[System.Management.Automation.Language.Ast]$AST,
@@ -27,52 +27,58 @@ function MoveUsingStatements {
2727

2828
# The encoding defaults to UTF8 (or UTF8NoBom on Core)
2929
[Parameter(DontShow)]
30-
[string]$Encoding = $(if ($IsCoreCLR) { "UTF8NoBom" } else { "UTF8" })
30+
[string]$Encoding = $(if ($IsCoreCLR) {
31+
"UTF8NoBom"
32+
} else {
33+
"UTF8"
34+
})
3135
)
36+
process {
37+
# Avoid modifying the file if there's no Parsing Error caused by Using Statements or other errors
38+
if (!$ParseErrors.Where{ $_.ErrorId -eq 'UsingMustBeAtStartOfScript' }) {
39+
Write-Debug "No using statement errors found."
40+
return
41+
} else {
42+
# as decided https://github.com/PoshCode/ModuleBuilder/issues/96
43+
Write-Debug "Parsing errors found. We'll still attempt to Move using statements."
44+
}
3245

33-
# Avoid modifying the file if there's no Parsing Error caused by Using Statements or other errors
34-
if (!$ParseErrors.Where{$_.ErrorId -eq 'UsingMustBeAtStartOfScript'}) {
35-
Write-Debug "No using statement errors found."
36-
return
37-
}
38-
# Avoid modifying the file if there's other parsing errors than Using Statements misplaced
39-
if ($ParseErrors.Where{$_.ErrorId -ne 'UsingMustBeAtStartOfScript'}) {
40-
Write-Warning "Parsing errors found. Skipping moving using statements."
41-
return
42-
}
43-
44-
# Find all Using statements including those non erroring (to conserve their order)
45-
$UsingStatementExtents = $AST.FindAll(
46-
{$Args[0] -is [System.Management.Automation.Language.UsingStatementAst]},
47-
$false
48-
).Extent
46+
# Find all Using statements including those non erroring (to conserve their order)
47+
$UsingStatementExtents = $AST.FindAll(
48+
{ $Args[0] -is [System.Management.Automation.Language.UsingStatementAst] },
49+
$false
50+
).Extent
4951

50-
# Edit the Script content by commenting out existing statements (conserving line numbering)
51-
$ScriptText = $AST.Extent.Text
52-
$InsertedCharOffset = 0
53-
$StatementsToCopy = New-Object System.Collections.ArrayList
54-
foreach ($UsingSatement in $UsingStatementExtents) {
55-
$ScriptText = $ScriptText.Insert($UsingSatement.StartOffset + $InsertedCharOffset, '#')
56-
$InsertedCharOffset++
52+
# Edit the Script content by commenting out existing statements (conserving line numbering)
53+
$ScriptText = $AST.Extent.Text
54+
$InsertedCharOffset = 0
55+
$StatementsToCopy = New-Object System.Collections.ArrayList
56+
foreach ($UsingSatement in $UsingStatementExtents) {
57+
$ScriptText = $ScriptText.Insert($UsingSatement.StartOffset + $InsertedCharOffset, '#')
58+
$InsertedCharOffset++
5759

58-
# Keep track of unique statements we'll need to insert at the top
59-
if (!$StatementsToCopy.Contains($UsingSatement.Text)) {
60-
$null = $StatementsToCopy.Add($UsingSatement.Text)
60+
# Keep track of unique statements we'll need to insert at the top
61+
if (!$StatementsToCopy.Contains($UsingSatement.Text)) {
62+
$null = $StatementsToCopy.Add($UsingSatement.Text)
63+
}
6164
}
62-
}
6365

64-
$ScriptText = $ScriptText.Insert(0, ($StatementsToCopy -join "`r`n") + "`r`n")
66+
$ScriptText = $ScriptText.Insert(0, ($StatementsToCopy -join "`r`n") + "`r`n")
67+
$null = Set-Content -Value $ScriptText -Path $RootModule -Encoding $Encoding
6568

66-
# Verify we haven't introduced new Parsing errors
67-
$null = [System.Management.Automation.Language.Parser]::ParseInput(
68-
$ScriptText,
69-
[ref]$null,
70-
[ref]$ParseErrors
71-
)
69+
# Verify we haven't introduced new Parsing errors
70+
$null = [System.Management.Automation.Language.Parser]::ParseFile(
71+
$RootModule,
72+
[ref]$null,
73+
[ref]$ParseErrors
74+
)
7275

73-
if ($ParseErrors) {
74-
Write-Warning "We introduced parsing error(s) while attempting to move using statements. Cancelling changes."
75-
} else {
76-
$null = Set-Content -Value $ScriptText -Path $RootModule -Encoding $Encoding
76+
if ($ParseErrors.Count) {
77+
$Message = $ParseErrors |
78+
Format-Table -Auto @{n = "File"; expr = { $_.Extent.File | Split-Path -Leaf }},
79+
@{n = "Line"; expr = { $_.Extent.StartLineNumber }},
80+
Extent, ErrorId, Message | Out-String
81+
Write-Warning "Parse errors in build output:`n$Message"
82+
}
7783
}
7884
}

Source/Private/SetModuleContent.ps1

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ function SetModuleContent {
1010
1111
The goal here is to pretend this is a pipeline, for the sake of memory and file IO
1212
#>
13+
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSReviewUnusedParameter", "OutputPath", Justification = "The rule is buggy")]
14+
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSReviewUnusedParameter", "Encoding", Justification = "The rule is buggy ")]
1315
[CmdletBinding()]
1416
param(
1517
# Where to write the joined output
@@ -37,7 +39,7 @@ function SetModuleContent {
3739

3840
# Create a proxy command style scriptblock for Set-Content to keep the file handle open
3941
$SetContentCmd = $ExecutionContext.InvokeCommand.GetCommand('Microsoft.PowerShell.Management\Set-Content', [System.Management.Automation.CommandTypes]::Cmdlet)
40-
$SetContent = {& $SetContentCmd -Path $OutputPath -Encoding $Encoding }.GetSteppablePipeline($myInvocation.CommandOrigin)
42+
$SetContent = {& $SetContentCmd -Path $OutputPath -Encoding $Encoding}.GetSteppablePipeline($myInvocation.CommandOrigin)
4143
$SetContent.Begin($true)
4244
}
4345
process {

Source/Public/Build-Module.ps1

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ function Build-Module {
3737
#>
3838
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "", Justification="Build is approved now")]
3939
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseCmdletCorrectly", "")]
40+
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSReviewUnusedParameter", "", Justification="Parameter handling is in InitializeBuild")]
4041
[CmdletBinding(DefaultParameterSetName="SemanticVersion")]
4142
[Alias("build")]
4243
param(

Source/Public/Convert-CodeCoverage.ps1

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,7 @@ function Convert-CodeCoverage {
1717
# The output of `Invoke-Pester -Pasthru`
1818
# Note: Pester doesn't apply a custom type name
1919
[Parameter(ValueFromPipeline)]
20-
[PSObject]$InputObject,
21-
22-
# Output paths as short paths, relative to the SourceRoot
23-
[switch]$Relative
20+
[PSObject]$InputObject
2421
)
2522
process {
2623
Push-Location $SourceRoot

Source/Public/Convert-LineNumber.ps1

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,7 @@ function Convert-LineNumber {
2525
[psobject]$InputObject,
2626

2727
[Parameter(ParameterSetName="FromInvocationInfo")]
28-
[switch]$Passthru,
29-
30-
# Output paths as short paths, relative to the SourceRoot
31-
[switch]$Relative
28+
[switch]$Passthru
3229
)
3330
begin {
3431
$filemap = @{}
@@ -42,14 +39,12 @@ function Convert-LineNumber {
4239
if(!(Test-Path $SourceFile)) {
4340
throw "'$SourceFile' does not exist"
4441
}
45-
$PSScriptRoot = Split-Path $SourceFile
46-
47-
Push-Location $PSScriptRoot
42+
Push-Location (Split-Path $SourceFile)
4843
try {
4944
if (!$filemap.ContainsKey($SourceFile)) {
5045
# Note: the new pattern is #Region but the old one was # BEGIN
51-
$matches = Select-String '^(?:#Region|# BEGIN) (?<SourceFile>.*) (?<LineNumber>\d+)?$' -Path $SourceFile
52-
$filemap[$SourceFile] = @($matches.ForEach{
46+
$regions = Select-String '^(?:#Region|# BEGIN) (?<SourceFile>.*) (?<LineNumber>\d+)?$' -Path $SourceFile
47+
$filemap[$SourceFile] = @($regions.ForEach{
5348
[PSCustomObject]@{
5449
PSTypeName = "BuildSourceMapping"
5550
SourceFile = $_.Matches[0].Groups["SourceFile"].Value.Trim("'")

Tests/Private/MoveUsingStatements.Tests.ps1

Lines changed: 13 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,23 @@ Describe "MoveUsingStatements" {
5656
ErrorAfter = 0
5757
},
5858
@{
59-
TestCaseName = 'Not move anything if there are (other) parse errors'
59+
TestCaseName = 'Move using statements even if types are used'
60+
PSM1File = "function x {`r`n}`r`n" +
61+
"using namespace System.IO`r`n`r`n" + #UsingMustBeAtStartOfScript
62+
"function y {`r`n}`r`n" +
63+
"using namespace System.Collections.Generic" + #UsingMustBeAtStartOfScript
64+
"function z { [Dictionary[String,PSObject]]::new() }" #TypeNotFound
65+
ErrorBefore = 3
66+
ErrorAfter = 0
67+
},
68+
@{
69+
TestCaseName = 'Move using statements even when there are (other) parse errors'
6070
PSM1File = "using namespace System.IO`r`n`r`n" +
6171
"function x { `r`n}`r`n" +
6272
"using namespace System.Drawing`r`n" + # UsingMustBeAtStartOfScript
6373
"function y { `r`n}`r`n}" # Extra } at the end
6474
ErrorBefore = 2
65-
ErrorAfter = 2
75+
ErrorAfter = 1
6676
}
6777
)
6878

@@ -91,6 +101,7 @@ Describe "MoveUsingStatements" {
91101
$ErrorFound.Count | Should -Be $ErrorAfter
92102
}
93103
}
104+
94105
Context "When MoveUsingStatements should do nothing" {
95106

96107
$MoveUsingStatementsCmd = InModuleScope ModuleBuilder {
@@ -103,16 +114,6 @@ Describe "MoveUsingStatements" {
103114
}
104115
}
105116

106-
It 'Should Warn and skip when there are Parsing errors other than Using Statements' {
107-
$testModuleFile = "$TestDrive/MyModule.psm1"
108-
$PSM1File = "Using namespace System.IO`r`n function xyz {}`r`n}`r`nUsing namespace System.Drawing" # extra } Set-Content $testModuleFile -value $PSM1File -Encoding UTF8
109-
Set-Content $testModuleFile -value $PSM1File -Encoding UTF8
110-
111-
&$MoveUsingStatementsCmd -RootModule $testModuleFile
112-
Assert-MockCalled -CommandName Write-Warning -Times 1 -ModuleName ModuleBuilder
113-
Assert-MockCalled -CommandName Set-Content -Times 0 -ModuleName ModuleBuilder
114-
}
115-
116117
It 'Should not do anything when there are no using statement errors' {
117118
$testModuleFile = "$TestDrive\MyModule.psm1"
118119
$PSM1File = "using namespace System.IO; function x {}"
@@ -125,29 +126,5 @@ Describe "MoveUsingStatements" {
125126
Assert-MockCalled -CommandName Set-Content -Times 0 -ModuleName ModuleBuilder
126127
Assert-MockCalled -CommandName Write-Debug -Times 1 -ModuleName ModuleBuilder
127128
}
128-
129-
130-
It 'Should not modify file when introducing parsing errors' {
131-
132-
$testModuleFile = "$TestDrive\MyModule.psm1"
133-
$PSM1File = "function x {}`r`nUsing namespace System.IO;"
134-
Set-Content $testModuleFile -value $PSM1File -Encoding UTF8
135-
136-
InModuleScope ModuleBuilder {
137-
$null = Mock New-Object {
138-
# Introducing Parsing Error in the file
139-
$Flag = [System.Collections.ArrayList]::new()
140-
$null = $Flag.Add("MyParsingError}")
141-
$PSCmdlet.WriteObject($Flag, $false)
142-
}
143-
}
144-
145-
&$MoveUsingStatementsCmd -RootModule $testModuleFile
146-
147-
Assert-MockCalled -CommandName Set-Content -Times 0 -ModuleName ModuleBuilder
148-
Assert-MockCalled -CommandName Write-Warning -Times 1 -ModuleName ModuleBuilder
149-
(Get-Content -Raw $testModuleFile).Trim() | Should -Be $PSM1File
150-
151-
}
152129
}
153130
}

0 commit comments

Comments
 (0)