Tasks/ModuleConventions/PublicFunctions.ps1
|
<# .SYNOPSIS Validates all public functions are declared in the PSD1. .DESCRIPTION Checks files under `Public` and fails when a public function file name is not listed in the manifest `FunctionsToExport` value, an exported function has no matching public file, a public file does not define a matching function, or a private function is exported. .GROUP ModuleConventions .CONFIGURATION `ModuleManifest` controls which module manifest supplies `FunctionsToExport`. ### Example ```powershell . (Get-PlumberTaskLoader) -Config @{ ModuleManifest = 'MyModule.psd1' } ``` .RUN ```powershell Invoke-Plumber -Task PublicFunctions ``` .PASS ```powershell FunctionsToExport = @('Get-Thing') ``` .FAIL ```powershell FunctionsToExport = @() ``` #> Add-BuildTask -Name PublicFunctions -Jobs SetVariables, { $exportedFunctions = @($script:psd1.FunctionsToExport) $publicRoot = Join-Path $BuildRoot 'Public' $privateRoot = Join-Path $BuildRoot 'Private' $publicFiles = if (Test-Path $publicRoot) { @(Get-ChildItem $publicRoot -File -Filter '*.ps1') } else { @() } $privateFiles = if (Test-Path $privateRoot) { @(Get-ChildItem $privateRoot -File -Filter '*.ps1') } else { @() } $publicFunctionNames = @($publicFiles | Select-Object -ExpandProperty BaseName) $failures = foreach ($publicFile in $publicFiles) { if ($publicFile.BaseName -notin $exportedFunctions) { "$($publicFile.BaseName) is not in FunctionsToExport" } $tokens = $null $parseErrors = $null $ast = [System.Management.Automation.Language.Parser]::ParseFile( $publicFile.FullName, [ref]$tokens, [ref]$parseErrors ) if ($parseErrors) { "$($publicFile.Name) could not be parsed" continue } $functionNames = @($ast.FindAll( { param ($node) $node -is [System.Management.Automation.Language.FunctionDefinitionAst] }, $true ) | Select-Object -ExpandProperty Name) if ($publicFile.BaseName -notin $functionNames) { "$($publicFile.Name) does not define function $($publicFile.BaseName)" } } $failures += foreach ($exportedFunction in $exportedFunctions) { if ($exportedFunction -notin $publicFunctionNames) { "$exportedFunction is exported but Public/$exportedFunction.ps1 was not found" } } $failures += foreach ($privateFile in $privateFiles) { $tokens = $null $parseErrors = $null $ast = [System.Management.Automation.Language.Parser]::ParseFile( $privateFile.FullName, [ref]$tokens, [ref]$parseErrors ) if ($parseErrors) { "$($privateFile.Name) could not be parsed" continue } $privateFunctionNames = @($ast.FindAll( { param ($node) $node -is [System.Management.Automation.Language.FunctionDefinitionAst] }, $true ) | Select-Object -ExpandProperty Name) foreach ($privateFunctionName in $privateFunctionNames) { if ($privateFunctionName -in $exportedFunctions) { "$privateFunctionName is exported from Private/$($privateFile.Name)" } } } if ($failures) { Write-Error ($failures -join (', ' + [Environment]::NewLine)) } } |