Private/Read-ForgeConfiguration.ps1

function Read-ForgeConfiguration {
    <#
    .SYNOPSIS
        Reads, parses, and validates a ChocoForge YAML configuration file.
 
    .DESCRIPTION
        Loads a ChocoForge YAML configuration file, parses it, and validates that all required fields and structure are present.
         
        If no path is provided, the function will search for a single .forge.yaml file in the current directory.
         
        Returns the parsed configuration as a PowerShell custom object.
 
        Required fields include:
        - 'package'
        - 'releases.source' (must be a GitHub URL)
        - At least one 'releases.flavors' entry (each must have 'versionPattern' and 'assetsPattern')
        - At least one 'sources' entry (each must have 'url' and 'apiKey')
 
    .PARAMETER Path
        Path to the YAML configuration file. If not provided, the function will search for a single .forge.yaml file in the current directory.
 
    .EXAMPLE
        Read-ForgeConfiguration -Path 'Samples/firebird.forge.yaml'
         
        Loads and validates the specified configuration file.
 
    .EXAMPLE
        Read-ForgeConfiguration
         
        Auto-discovers and loads a .forge.yaml file in the current directory if only one exists.
 
    .OUTPUTS
        PSCustomObject
        The parsed and validated configuration object.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [string]$Path
    )

    if (-not $Path) {
        Write-VerboseMark 'No path provided. Searching for .forge.yaml files in current directory.'
        $forgeFiles = Get-ChildItem -Path (Get-Location) -Filter '*.forge.yaml' | Select-Object -ExpandProperty FullName
        if ($forgeFiles.Count -eq 0) {
            throw 'No .forge.yaml file found in the current directory.'
        } elseif ($forgeFiles.Count -gt 1) {
            throw 'Multiple .forge.yaml files found in the current directory. Please specify one.'
        }
        $Path = $forgeFiles[0]
    }

    if (-not (Test-Path $Path)) {
        throw "YAML configuration file not found: $Path"
    }
    Write-VerboseMark "Using configuration file: $($Path)"
    $config = ConvertFrom-Yaml (Get-Content -Raw -LiteralPath $Path) -Ordered

    # Validate 'package'
    if (-not $config.package) {
        throw "Missing required 'package' property in YAML configuration."
    }

    # Validate 'releases.source' (must be a GitHub URL)
    if (-not $config.releases -or -not $config.releases.source) {
        throw "Missing required 'releases.source' property."
    }
    if ($config.releases.source -notmatch '^https://github.com/.+') {
        throw "'releases.source' must be a GitHub repository URL."
    }

    # Validate 'releases.flavors' (at least one flavor, each with versionPattern and assetsPattern)
    if (-not $config.releases.flavors -or $config.releases.flavors.Count -eq 0) {
        throw "At least one 'releases.flavors' entry is required."
    }
    foreach ($flavorName in $config.releases.flavors.Keys) {
        $flavor = $config.releases.flavors[$flavorName]
        $patterns = @{}
        foreach ($item in $flavor) {
            if ($item.versionPattern) { $patterns.versionPattern = $item.versionPattern }
            if ($item.assetsPattern) { $patterns.assetsPattern = $item.assetsPattern }
        }
        if (-not $patterns.versionPattern) {
            throw "Flavor '$flavorName' is missing 'versionPattern'."
        }
        if (-not $patterns.assetsPattern) {
            throw "Flavor '$flavorName' is missing 'assetsPattern'."
        }
    }

    # Validate 'sources' (at least one, each with url and apiKey)
    if (-not $config.sources -or $config.sources.Count -eq 0) {
        throw "At least one 'sources' entry is required."
    }
    foreach ($sourceName in $config.sources.Keys) {
        $source = $config.sources[$sourceName]
        if (-not $source.url) {
            throw "Source '$sourceName' is missing 'url'."
        }
        if (-not $source.apiKey) {
            throw "Source '$sourceName' is missing 'apiKey'."
        }
    }

    Write-VerboseMark -Message 'YAML configuration validated successfully.'
    return $config
}