build.ps1

#Requires -Version 7.0
param(
    [string]$SourcePath = "$PSScriptRoot/src",
    [string]$OutputPath = "$PSScriptRoot/bin",
    [string]$MetadataPath = "$PSScriptRoot/metadata.json"
)

$ErrorActionPreference = 'Stop'

Write-Host "Starting build process..." -ForegroundColor Cyan

# Ensure output directory exists
if (-not (Test-Path $OutputPath)) {
    New-Item -Path $OutputPath -ItemType Directory -Force | Out-Null
}

# Read metadata
if (-not (Test-Path $MetadataPath)) {
    throw "Metadata file not found at $MetadataPath"
}
$metadata = Get-Content $MetadataPath -Raw | ConvertFrom-Json

# Initialize PSM1 content
$psm1Content = [System.Text.StringBuilder]::new()

# 1. Add Header
$psm1Content.AppendLine("#Requires -Version $($metadata.PowerShellVersion)") | Out-Null
$psm1Content.AppendLine("<#") | Out-Null
$psm1Content.AppendLine(".SYNOPSIS") | Out-Null
$psm1Content.AppendLine(" $($metadata.Description)") | Out-Null
$psm1Content.AppendLine(".NOTES") | Out-Null
$psm1Content.AppendLine(" Version: $($metadata.ModuleVersion)") | Out-Null
$psm1Content.AppendLine(" Author: $($metadata.Author)") | Out-Null
$psm1Content.AppendLine(" Copyright: $($metadata.Copyright)") | Out-Null
$psm1Content.AppendLine("#>") | Out-Null
$psm1Content.AppendLine("") | Out-Null

# 2. Add Startup Script
$startupPath = Join-Path $SourcePath "Startup.ps1"
if (Test-Path $startupPath) {
    Write-Host "Adding Startup.ps1..." -ForegroundColor Green
    $psm1Content.AppendLine("# region Startup") | Out-Null
    $psm1Content.AppendLine((Get-Content $startupPath -Raw)) | Out-Null
    $psm1Content.AppendLine("# endregion Startup") | Out-Null
    $psm1Content.AppendLine("") | Out-Null
}

# 3. Add Private Functions
$privateFiles = Get-ChildItem -Path (Join-Path $SourcePath "private") -Filter "*.ps1" -Recurse
foreach ($file in $privateFiles) {
    Write-Host "Adding Private function: $($file.Name)" -ForegroundColor Gray
    $psm1Content.AppendLine("# region Private: $($file.Name)") | Out-Null
    $psm1Content.AppendLine((Get-Content $file.FullName -Raw)) | Out-Null
    $psm1Content.AppendLine("# endregion Private: $($file.Name)") | Out-Null
    $psm1Content.AppendLine("") | Out-Null
}

# 4. Add Public Functions and collect names for export
$publicFiles = Get-ChildItem -Path (Join-Path $SourcePath "public") -Filter "*.ps1" -Recurse
$functionsToExport = @()

foreach ($file in $publicFiles) {
    Write-Host "Adding Public function: $($file.Name)" -ForegroundColor Green
    $psm1Content.AppendLine("# region Public: $($file.Name)") | Out-Null
    $psm1Content.AppendLine((Get-Content $file.FullName -Raw)) | Out-Null
    $psm1Content.AppendLine("# endregion Public: $($file.Name)") | Out-Null
    $psm1Content.AppendLine("") | Out-Null

    $functionsToExport += $file.BaseName
}

# 5. Export Module Members
$psm1Content.AppendLine("Export-ModuleMember -Function @(") | Out-Null
$exportList = $functionsToExport | ForEach-Object { " '$_'" }
$psm1Content.AppendLine(($exportList -join ",`n")) | Out-Null
$psm1Content.AppendLine(") -Alias @('aither')") | Out-Null
$psm1Content.AppendLine("") | Out-Null

# 5b. Post-init: Load deferred plugins discovered during Startup
$psm1Content.AppendLine("# region Post-Init: Deferred Plugin Loading") | Out-Null
$psm1Content.AppendLine("if (`$script:_PendingPluginPaths) {") | Out-Null
$psm1Content.AppendLine(" foreach (`$pendingPath in `$script:_PendingPluginPaths) {") | Out-Null
$psm1Content.AppendLine(" try {") | Out-Null
$psm1Content.AppendLine(" Register-AitherPlugin -Path `$pendingPath -ErrorAction SilentlyContinue") | Out-Null
$psm1Content.AppendLine(" } catch {") | Out-Null
$psm1Content.AppendLine(" Write-Verbose `"Auto-load plugin from '`$pendingPath' failed: `$_`"") | Out-Null
$psm1Content.AppendLine(" }") | Out-Null
$psm1Content.AppendLine(" }") | Out-Null
$psm1Content.AppendLine(" Remove-Variable -Name '_PendingPluginPaths' -Scope Script -ErrorAction SilentlyContinue") | Out-Null
$psm1Content.AppendLine("}") | Out-Null
$psm1Content.AppendLine("# endregion Post-Init") | Out-Null
$psm1Content.AppendLine("") | Out-Null

# Write PSM1
$psm1Path = Join-Path $OutputPath "AitherZero.psm1"
Set-Content -Path $psm1Path -Value $psm1Content.ToString()
Write-Host "Created $psm1Path" -ForegroundColor Cyan

# Copy to root for development convenience
$rootPsm1Path = Join-Path $PSScriptRoot "AitherZero.psm1"
Copy-Item -Path $psm1Path -Destination $rootPsm1Path -Force
Write-Host "Updated root module: $rootPsm1Path" -ForegroundColor Cyan

# 6. Generate PSD1
$psd1Path = Join-Path $OutputPath "AitherZero.psd1"
$manifest = @{
    RootModule = "AitherZero.psm1"
    ModuleVersion = $metadata.ModuleVersion
    GUID = $metadata.GUID
    Author = $metadata.Author
    CompanyName = $metadata.CompanyName
    Copyright = $metadata.Copyright
    Description = $metadata.Description
    PowerShellVersion = $metadata.PowerShellVersion
    CompatiblePSEditions = $metadata.CompatiblePSEditions
    FunctionsToExport = $functionsToExport
    CmdletsToExport = @()
    VariablesToExport = '*'
    AliasesToExport = @()
}

# Helper to format array for PSD1
function Format-Psd1Array {
    param($Array, $Indent = 8)
    if ($null -eq $Array -or $Array.Count -eq 0) { return "@()" }
    $spaces = " " * $Indent
    $items = $Array | ForEach-Object { "$spaces'$_'" }
    return "@(`n" + ($items -join "`n") + "`n$($spaces.Substring(0, $spaces.Length - 4)))"
}

# Create PSD1 content manually to ensure proper formatting
$psd1Content = @"
@{
    RootModule = '$($manifest.RootModule)'
    ModuleVersion = '$($manifest.ModuleVersion)'
    GUID = '$($manifest.GUID)'
    Author = '$($manifest.Author)'
    CompanyName = '$($manifest.CompanyName)'
    Copyright = '$($manifest.Copyright)'
    Description = '$($manifest.Description)'
    PowerShellVersion = '$($manifest.PowerShellVersion)'
    CompatiblePSEditions = $(Format-Psd1Array $manifest.CompatiblePSEditions)
    FunctionsToExport = $(Format-Psd1Array $manifest.FunctionsToExport)
    CmdletsToExport = @()
    VariablesToExport = '*'
    AliasesToExport = @()
}
"@


Set-Content -Path $psd1Path -Value $psd1Content
Write-Host "Created $psd1Path" -ForegroundColor Cyan

# Copy to root for development convenience
$rootPsd1Path = Join-Path $PSScriptRoot "AitherZero.psd1"
Set-Content -Path $rootPsd1Path -Value $psd1Content
Write-Host "Updated root manifest: $rootPsd1Path" -ForegroundColor Cyan

Write-Host "Build complete!" -ForegroundColor Green