diff --git a/Source/Private/SetModuleContent.ps1 b/Source/Private/SetModuleContent.ps1 index fc92966..638423e 100644 --- a/Source/Private/SetModuleContent.ps1 +++ b/Source/Private/SetModuleContent.ps1 @@ -34,6 +34,10 @@ function SetModuleContent { ) begin { Write-Debug "SetModuleContent WorkingDirectory $WorkingDirectory" + # Windows PowerShell's Set-Content has no UTF8Bom encoding, but its UTF8 encoding writes a BOM + if (-not $IsCoreCLR -and $Encoding -eq "UTF8Bom") { + $Encoding = "UTF8" + } Write-Debug "Encoding $Encoding" Push-Location $WorkingDirectory -StackName SetModuleContent $ContentStarted = $false # There has been no content yet diff --git a/Source/Public/ConvertTo-Script.ps1 b/Source/Public/ConvertTo-Script.ps1 index ce69239..0614c38 100644 --- a/Source/Public/ConvertTo-Script.ps1 +++ b/Source/Public/ConvertTo-Script.ps1 @@ -87,6 +87,10 @@ function ConvertTo-Script { } } + # Windows PowerShell's Set-Content has no UTF8Bom encoding, but its UTF8 encoding writes a BOM + if (-not $IsCoreCLR -and $Encoding -eq "UTF8Bom") { + $Encoding = "UTF8" + } $SetContentCmd = $ExecutionContext.InvokeCommand.GetCommand('Microsoft.PowerShell.Management\Set-Content', [System.Management.Automation.CommandTypes]::Cmdlet) Write-Debug " EXIT: ConvertTo-Script BEGIN" } diff --git a/Source/Public/Invoke-ScriptGenerator.ps1 b/Source/Public/Invoke-ScriptGenerator.ps1 index dcea7b1..3e5ea41 100644 --- a/Source/Public/Invoke-ScriptGenerator.ps1 +++ b/Source/Public/Invoke-ScriptGenerator.ps1 @@ -82,6 +82,10 @@ function Invoke-ScriptGenerator { $null = $AstParam.Remove("Encoding") $ParseResults = ConvertToAst @AstParam [StringBuilder]$Builder = $ParseResults.Ast.Extent.Text + # Windows PowerShell's Set-Content has no UTF8Bom encoding, but its UTF8 encoding writes a BOM + if (-not $IsCoreCLR -and $Encoding -eq "UTF8Bom") { + $Encoding = "UTF8" + } $SetContentCmd = $ExecutionContext.InvokeCommand.GetCommand('Microsoft.PowerShell.Management\Set-Content', [System.Management.Automation.CommandTypes]::Cmdlet) } process { diff --git a/Tests/Integration/Source1.Tests.ps1 b/Tests/Integration/Source1.Tests.ps1 index bcb285a..93760f9 100644 --- a/Tests/Integration/Source1.Tests.ps1 +++ b/Tests/Integration/Source1.Tests.ps1 @@ -359,3 +359,35 @@ Describe "Regression test for #125: SourceDirectories supports wildcards" -Tag I $Metadata.FunctionsToExport | Should -Be @("Get-Source", "Set-Source") } } + +Describe "Regression test for UTF8Bom encoding on Windows PowerShell" -Tag Integration, Regression { + BeforeAll { + # The non-ASCII string returned by Source1's Set-Source + $NonAscii = "sto$([char]0x35E)o$([char]0x2032)p$([char]0x12D)d" + + Copy-Item $PSScriptRoot\Source1 TestDrive:\Utf8BomParameter -Recurse + $ParameterOutput = Build-Module TestDrive:\Utf8BomParameter -Encoding UTF8Bom -OutputDirectory "$TestDrive\Utf8BomParameterOutput" -Passthru -ErrorAction Stop + $ParameterModule = [IO.Path]::ChangeExtension($ParameterOutput.Path, "psm1") + + # Values from build.psd1 are not checked by the Encoding parameter's ValidateSet + Copy-Item $PSScriptRoot\Source1 TestDrive:\Utf8BomManifest -Recurse + $metadata = Import-Metadata TestDrive:\Utf8BomManifest\build.psd1 + $metadata["Encoding"] = "UTF8Bom" + $metadata["OutputDirectory"] = "$TestDrive\Utf8BomManifestOutput" + $metadata | Export-Metadata TestDrive:\Utf8BomManifest\build.psd1 + $ManifestOutput = Build-Module TestDrive:\Utf8BomManifest -Passthru -ErrorAction Stop + $ManifestModule = [IO.Path]::ChangeExtension($ManifestOutput.Path, "psm1") + } + + It "Writes a BOM and UTF-8 content when UTF8Bom is passed as a parameter" { + $Bytes = [IO.File]::ReadAllBytes($ParameterModule) + $Bytes[0..2] | Should -Be @(0xEF, 0xBB, 0xBF) + [IO.File]::ReadAllText($ParameterModule, [Text.Encoding]::UTF8) | Should -Match ([regex]::Escape($NonAscii)) + } + + It "Writes a BOM and UTF-8 content when UTF8Bom is set in build.psd1" { + $Bytes = [IO.File]::ReadAllBytes($ManifestModule) + $Bytes[0..2] | Should -Be @(0xEF, 0xBB, 0xBF) + [IO.File]::ReadAllText($ManifestModule, [Text.Encoding]::UTF8) | Should -Match ([regex]::Escape($NonAscii)) + } +} diff --git a/Tests/Public/ConvertTo-Script.Tests.ps1 b/Tests/Public/ConvertTo-Script.Tests.ps1 index 5825aea..0bb18d6 100644 --- a/Tests/Public/ConvertTo-Script.Tests.ps1 +++ b/Tests/Public/ConvertTo-Script.Tests.ps1 @@ -23,5 +23,12 @@ Describe "ConvertTo-Script" { $ScriptFileCommand = Get-Command $ScriptFile $ScriptFileCommand.Parameters.Keys | Sort-Object | Should -Be ($BuildModuleCommand.Parameters.Keys | Sort-Object) } + + It "Accepts UTF8Bom encoding on every edition" { + Remove-Item $ScriptFile -ErrorAction Ignore + $null = Invoke-ScriptGenerator -Path $ModuleBuilder.Path -Generator "ConvertTo-Script" -Parameters @{ FunctionName = "Build-Module"; Encoding = "UTF8Bom" } -ErrorAction Stop + + $ScriptFile | Should -Exist + } } }