build.ps1

[CmdletBinding()]
param ()

# Extract the name of the module
$moduleName = $PSScriptRoot | Split-Path -Leaf

# Ensure that module manifest exists
$moduleManifestPath = "$($PSScriptRoot)\$moduleName.psd1"
if (!(Test-Path -Path "$($moduleManifestPath)" -ErrorAction SilentlyContinue)) {
    Write-Error "Module manifest '$($moduleManifestPath)' does not exist."
    exit
}

# Retrieve the contents of the module manifest
Write-Information "Retrieving the module manifest '$($moduleManifestPath)'."
$moduleManifest = Get-Content -Path $moduleManifestPath -Raw
if ([String]::IsNullOrWhiteSpace($moduleManifest)) {
    Write-Error "Module manifest '$($moduleManifestPath)' is null or whitespace."
    exit
}

# Ensure that NestedModules and FunctionsToExport are not commented out, and un-comment if they are
if ([Regex]::new("#[ ]{0,1}NestedModules").IsMatch($moduleManifest)) {
    $moduleManifest = $moduleManifest -replace "#[ ]{0,1}NestedModules", "NestedModules"
}
if ([Regex]::new("#[ ]{0,1}FunctionsToExport").IsMatch($moduleManifest)) {
    $moduleManifest = $moduleManifest -replace "#[ ]{0,1}FunctionsToExport", "FunctionsToExport"
}

# Keep track of the nested modules and functions to export
$nestedModules = @()
$functionsToExport = @()

# Extract the private functions (if any)
Write-Information "Processing private functions."
$privateFunctionDirectory = "$($PSScriptRoot)\PrivateFunctions"
if (Test-Path -Path $privateFunctionDirectory -ErrorAction SilentlyContinue) {
    $privateFunctionPaths = (Get-ChildItem -Path $privateFunctionDirectory -File).FullName `
        | Where-Object { $_ -like "*.ps1" -and $_ -notLike "*.Tests.ps1" }

    # Add the private functions to the list of nested modules but not the list of functions to export
    foreach ($privateFunctionPath in $privateFunctionPaths) {
        $privateFunctionFileName = $privateFunctionPath | Split-Path -Leaf
        $privateFunctionName = $privateFunctionFileName.Split(".")[0]
        Write-Verbose "Processing private function '$($privateFunctionName)'."
        $nestedModules += $privateFunctionFileName
    }
}

# Extract the exported functions (if any)
Write-Information "Processing exported functions."
$exportedFunctionDirectory = "$($PSScriptRoot)\Functions"
if (Test-Path -Path $exportedFunctionDirectory -ErrorAction SilentlyContinue) {
    $exportedFunctionPaths = (Get-ChildItem -Path $exportedFunctionDirectory -File).FullName `
        | Where-Object { $_ -like "*.ps1" -and $_ -notLike "*.Tests.ps1" }

    # Add the exported functions to the list of nested modules and the list of functions to export
    foreach ($exportedFunctionPath in $exportedFunctionPaths) {
        $exportedFunctionFileName = $exportedFunctionPath | Split-Path -Leaf
        $exportedFunctionName = $exportedFunctionFileName.Split(".")[0]
        Write-Verbose "Processing exported function '$($exportedFunctionName)'."
        $nestedModules += $exportedFunctionFileName
        $functionsToExport += $exportedFunctionName
    }
}

# Format nested modules into a string
$nestedModulesString = ""
if ($nestedModules.length -gt 1) {
    $nestedModulesString = "`r`n"
    $nestedModulesString += ($nestedModules | ForEach-Object -Process {
        " 'Functions/$($_)'"
    }) -join ",`r`n"
    $nestedModulesString += "`r`n"
}

# Format functions to export as a string
$functionsToExportString = ""
if ($functionsToExport.length -gt 1) {
    $functionsToExportString = "`r`n"
    $functionsToExportString += ($functionsToExport | ForEach-Object -Process {
        " '$($_)'"
    }) -join ",`r`n"
    $functionsToExportString += "`r`n"
}

# Replace the existing NestedModules and FunctionsToExport in the module manifest
Write-Information "Updating NestedModules and FunctionsToExport in the manifest."
$moduleManifest = $moduleManifest -replace "NestedModules = @\([\s\S]*?\)", "NestedModules = @($($nestedModulesString))"
$moduleManifest = $moduleManifest -replace "FunctionsToExport = @\([\s\S]*?\)", "FunctionsToExport = @($($functionsToExportString))"

# Update the content of the module manifest file
$moduleManifest | Set-Content -Path $moduleManifestPath -NoNewline