pf-module.ps1

$ErrorActionPreference = 'stop'

function Initialize-File_InNotPresent($path) {
    if (-not (Test-Path -Path $path)) {
        Set-Content -Path $path -Value ""
    }
}

function Get-Functions {
    param( 
        [Parameter(ValueFromPipeline=$true)]$path
    ) 
    process {
        $path = $path.FullName ?? $path
        . $path
        return Get-Command | Where-Object ScriptBlock |
            Where-Object { $_.ScriptBlock.File -eq $path } 
    }
}

function Get-ContentToInclude($functionName) {
    if ($functionName) {
        $header = get-command DefineModuleHeader
        $body = $header.ScriptBlock.ToString()
        $result = "#Include-Start $functionName`n$body`n#Include-end $functionName`n"
    }
    return $result
}

function Install-Module_BlockScope {
    Param(
        [string[]]$Name,
        [string[]]$repository = $Global:PSRepositoryLocal,
        [ScriptBlock]$script
    )
        if ($Name) {
            $missingModules = $Name | ForEach-Object { if (-not (Get-Module $_ -ListAvailable -SkipEditionCheck)) { $_ } }
        }
        try {
            if ($missingModules) {
                $moduleToRemove = $missingModules | ForEach-Object {
                    $repositorySelected = if ($repository) { $repository } else {
                        $candidateModules = find-module $_ | Sort-Object PublishedDate -Descending
                            | Select-Object -First 1
                        $candidateModules.Repository   
                    } 
                    Install-Module -Name $_ -Repository $repositorySelected -PassThru -AllowClobber 
                }
            }
            $script.InvokeReturnAsIs()
        }
        finally {
            if ($moduleToRemove) {
                $moduleToRemove | Uninstall-Module
            }
        }
}
function Install-Module_BlockScope:::Test {
    $moduleName = "pf-basic"
    Get-Module -Name $moduleName -ListAvailable | should -BeNullOrEmpty 
    $result = Install-Module_BlockScope -Name $moduleName -script {
        $mm = Get-Module -Name $moduleName -ListAvailable 
        $mm | should -not -BeNullOrEmpty
        Write-Host $mm
        Write-Output "Imported"
    }.GetNewClosure()
    write-host $result
    Get-Module -Name $moduleName -ListAvailable | should -BeNullOrEmpty 
}

function Remove-PowershellComments($path) {
    $content = Get-Content -Path $path -Raw
    $result = Remove-Script_Comments -content $content
    Set-Content -Path $path -Value $result -NoNewline
}

function Remove-Script_Comments($content) {
    $result = $content -replace '\s*#(?!\brequires\b).*', ''   
    $result = $result.Trim()
    return $result
}

function Remove-Script_Comments:::Test($content) {
    Remove-Script_Comments -content "#comment" | assert -eq ""
    Remove-Script_Comments -content "#requires" | assert -eq "#requires"
    Remove-Script_Comments -content " #comment abc" | assert -eq ""
    Remove-Script_Comments -content "abc" | assert -eq " abc"
}

function Add-Module_PSModulePath ([string]$ModulesFolder = 'PSModules', [switch]$notRequired ) {
    $p = split-path -parent ($current = ( Get-PSCallStack )[0].ScriptName )
    while ( $p -and -not ( Test-Path ( "$p\$ModulesFolder" ) ) ) { $p = Split-Path $p -Parent }
    if (-not $p -and -not $notRequired) { 
        throw "Modules folder '$ModulesFolder' cannot be found starting from '$current'" 
    } 
    $p = Resolve-Path "$p\$ModulesFolder"
    if (-not $env:PSModulePath.Contains("$p;")) { 
        $env:PSModulePath = "$p;$env:PSModulePath" 
    }
}

function Get-Modulefolders ($path) {
    $folders =  if ($path) { Get-ChildItem -Directory -path $path } 
                    else { Get-ChildItem -Directory }
    $folders |  Where-Object name -NotLike '.*'
}

function Sync-ModuleManifests([switch]$all, [switch]$UpdateRevision) {
    $commitCount = $UpdateRevision ? ( Get-GitCommitCount ) : $null
    $folders = Get-Modules_Local | Get-Path 
    if (-not $all) {
        $folders = $folders | Get-Git_Changed -folder
    }
    $folders | Initialize-Module_Manifest_EnsureFiles -Revision $commitCount
}

function Publish-ModuleEx {
    param(
        [Parameter(ValueFromPipeline=$true)]$ModuleBase,
        [string]$NuGetApiKey,
        [string[]]$repositoryList = @('LocalRepo')
    ) 
    process {
        $moduleName = Split-Path $ModuleBase -Leaf
        $psd = Import-PowerShellDataFile -Path "$ModuleBase\$moduleName.psd1" 
     
        foreach ($repository in $repositoryList) {
            $module = Find-Module  -Name $moduleName -RequiredVersion $psd.ModuleVersion `
                            -ErrorAction SilentlyContinue -Repository $repository
            if  (-not $module) {
                $additionalParams = @{}
                if ($NuGetApiKey) {
                    $additionalParams.Add("NuGetApiKey",$NuGetApiKey)
                }

                # Install-Module_BlockScope -script {
                    Publish-Module @additionalParams -Path $ModuleBase -Repository $repository -Force
                # }.GetNewClosure()

            }
        }
        
        $repository = $repositoryList[0]
        Uninstall-Module -Name $moduleName -ErrorAction SilentlyContinue
        
        # Install-Module -Name $moduleName -Scope CurrentUser -Repository $repository `
        # -Force -AllowClobber -RequiredVersion $psd.ModuleVersion
    }
}

function Publish-ModuleEx:::Example {
    $folderModules = Get-Modulefolders -path C:\code\PowerFrame 
    $folderModules.FullName | Initialize-Module_Manifest_EnsureFiles
    $folderModules.FullName | Publish-ModuleEx 
}

function Get-ScriptFunctions {
    param (
        [Parameter(ValueFromPipeline=$true)]
        $file
    )
    process {
        $file = $file.fullname ?? $file
        $Token = $null
        $ignoredOutput = [System.Management.Automation.Language.Parser]::ParseFile($File, [ref]$Token, [ref]$null)
        Write-Verbose $ignoredOutput
        $funcBegin = $false 
        $Token | ForEach-Object {
            if ($funcBegin) {
                $_.Text
            }
            $funcBegin = ($_.Kind -like "function") 
        }
    }
}
function Get-ScriptFunctions:::Example {
    Get-ChildItem pf-* -Recurse -Filter *.ps1 | Select-Object -First 1 | Get-ScriptFunctions
}

function Publish-ModuleBatch([switch]$Public, [switch]$all, $NuGetApiKey) {
    $folders = Get-Modules_Local | Get-Path 
    if (-not $all) {
        $folders = $folders | Get-Git_Changed -folder
    }
    $folders | ForEach-Object {
        if ($Public) {
            $_ | Publish-ModuleEx -NuGetApiKey $NuGetApiKey -Repository PSGallery
        }
        else {
            $_ | Publish-ModuleEx -Repository $PSRepositoryLocal
        }
    }
}