Public/Get-EnvkConfig.ps1

function Get-EnvkConfig {
    <#
    .SYNOPSIS
        Loads and validates the Envoke configuration file.
 
    .DESCRIPTION
        Public entry point for config loading. Resolves the config file path using
        Resolve-ConfigPath (three-location search order), reads and parses the JSON
        content, then validates the parsed object with Test-StartupConfig (collect-all
        validation). If any validation errors are found, all errors are reported together
        in a single terminating error.
 
        Validation warnings (unknown top-level keys) are logged but do not cause failure.
 
        The function returns the raw parsed config object. Environment/app merging and
        override resolution is deferred to the phase that consumes environments (Phase 6).
 
    .PARAMETER ConfigPath
        Optional. Explicit path to a config.json file. When provided, this path takes
        priority over all search locations. Throws a terminating error if the file does
        not exist or has a .jsonc extension.
 
    .OUTPUTS
        PSCustomObject
        The parsed config object with apps and environments properties.
 
    .EXAMPLE
        # Load config from default search locations (user data folder or module directory)
        $config = Get-EnvkConfig
 
    .EXAMPLE
        # Load config from an explicit path
        $config = Get-EnvkConfig -ConfigPath 'C:\Users\Aaron\config.json'
 
    .NOTES
        Author: Aaron AlAnsari
        Created: 2026-02-24
    #>


    [CmdletBinding()]
    [OutputType([PSCustomObject])]
    param (
        [Parameter()]
        [string]$ConfigPath
    )

    # Step 1 - Resolve path using three-location search order.
    $resolvedPath = Resolve-ConfigPath -ExplicitPath $ConfigPath
    Write-EnvkLog -Level 'DEBUG' -Message "Loading config from: $resolvedPath"

    # Step 2 - Read and parse JSON.
    try {
        $rawJson = Get-Content -Path $resolvedPath -Raw -Encoding UTF8
        $config  = $rawJson | ConvertFrom-Json
    }
    catch {
        Write-EnvkLog -Level 'ERROR' -Message "Failed to parse config file: $resolvedPath" -ErrorRecord $_
        throw
    }

    # Step 3 - Validate structure (collect-all).
    $validationResults = Test-StartupConfig -Config $config

    # Separate warnings (prefixed "WARNING: ") from errors.
    $warnings     = $validationResults | Where-Object { $_.StartsWith('WARNING: ') }
    $errorStrings = $validationResults | Where-Object { -not $_.StartsWith('WARNING: ') }

    foreach ($warning in $warnings) {
        Write-EnvkLog -Level 'WARNING' -Message ($warning -replace '^WARNING: ', '')
    }

    if ($errorStrings.Count -gt 0) {
        $combinedErrors = $errorStrings -join "`n"
        $message        = "Config validation failed with $($errorStrings.Count) error(s):`n$combinedErrors"
        Write-EnvkLog -Level 'ERROR' -Message $message
        throw $message
    }

    # Step 4 - Return config.
    Write-EnvkLog -Level 'INFO' -Message "Config loaded successfully from: $resolvedPath"
    return $config
}