Private/Resolve-HydrationSettingsSchema.ps1
|
function Resolve-HydrationSettingsSchema { [CmdletBinding()] param( [Parameter(Mandatory)] [hashtable]$Settings, [Parameter(Mandatory)] [hashtable]$Schema, [Parameter()] [string]$SchemaPath = 'root' ) function New-SettingsValidationError { param( [Parameter(Mandatory)] [string]$Message, [Parameter(Mandatory)] [string]$ErrorId, [Parameter(Mandatory)] [System.Management.Automation.ErrorCategory]$Category, [Parameter()] [object]$TargetObject ) $errorRecord = [System.Management.Automation.ErrorRecord]::new( [System.Exception]::new($Message), $ErrorId, $Category, $TargetObject ) $PSCmdlet.ThrowTerminatingError($errorRecord) } function Get-SchemaTypes { param( [Parameter()] [object]$TypeValue ) if ($null -eq $TypeValue) { return @() } if ($TypeValue -is [System.Array]) { return @($TypeValue) } return @($TypeValue) } function Test-ValueMatchesSchema { param( [Parameter()] [object]$Value, [Parameter(Mandatory)] [hashtable]$ValueSchema, [Parameter(Mandatory)] [string]$ValuePath ) $schemaTypes = Get-SchemaTypes -TypeValue $ValueSchema.type if ($null -eq $Value) { if ('null' -in $schemaTypes) { return } New-SettingsValidationError -Message "Property '$ValuePath' cannot be null." -ErrorId 'InvalidSettingsNull' -Category ([System.Management.Automation.ErrorCategory]::InvalidData) -TargetObject $ValuePath } if ('object' -in $schemaTypes) { if ($Value -isnot [System.Collections.IDictionary]) { New-SettingsValidationError -Message "Property '$ValuePath' must be an object." -ErrorId 'InvalidSettingsType' -Category ([System.Management.Automation.ErrorCategory]::InvalidData) -TargetObject $ValuePath } Resolve-SettingsObject -SettingsObject $Value -ObjectSchema $ValueSchema -ObjectPath $ValuePath return } if ('array' -in $schemaTypes) { if ($Value -isnot [System.Array]) { New-SettingsValidationError -Message "Property '$ValuePath' must be an array." -ErrorId 'InvalidSettingsType' -Category ([System.Management.Automation.ErrorCategory]::InvalidData) -TargetObject $ValuePath } if ($ValueSchema.items) { for ($i = 0; $i -lt $Value.Count; $i++) { Test-ValueMatchesSchema -Value $Value[$i] -ValueSchema $ValueSchema.items -ValuePath "$ValuePath[$i]" } } return } if ('string' -in $schemaTypes) { if ($Value -isnot [string]) { New-SettingsValidationError -Message "Property '$ValuePath' must be a string." -ErrorId 'InvalidSettingsType' -Category ([System.Management.Automation.ErrorCategory]::InvalidData) -TargetObject $ValuePath } if ($ValueSchema.enum -and $Value -notin $ValueSchema.enum) { New-SettingsValidationError -Message "Property '$ValuePath' must be one of: $($ValueSchema.enum -join ', ')." -ErrorId 'InvalidSettingsEnum' -Category ([System.Management.Automation.ErrorCategory]::InvalidData) -TargetObject $ValuePath } if ($ValueSchema.pattern -and $Value -notmatch $ValueSchema.pattern) { New-SettingsValidationError -Message "Property '$ValuePath' does not match the required format." -ErrorId 'InvalidSettingsPattern' -Category ([System.Management.Automation.ErrorCategory]::InvalidData) -TargetObject $ValuePath } return } if ('boolean' -in $schemaTypes) { if ($Value -isnot [bool]) { New-SettingsValidationError -Message "Property '$ValuePath' must be a boolean." -ErrorId 'InvalidSettingsType' -Category ([System.Management.Automation.ErrorCategory]::InvalidData) -TargetObject $ValuePath } } } function Resolve-SettingsObject { param( [Parameter(Mandatory)] [System.Collections.IDictionary]$SettingsObject, [Parameter(Mandatory)] [hashtable]$ObjectSchema, [Parameter(Mandatory)] [string]$ObjectPath ) foreach ($requiredProperty in @($ObjectSchema.required | Where-Object { $null -ne $_ })) { if (-not $SettingsObject.Contains($requiredProperty)) { New-SettingsValidationError -Message "Missing required field: $ObjectPath.$requiredProperty" -ErrorId 'MissingRequiredSetting' -Category ([System.Management.Automation.ErrorCategory]::InvalidData) -TargetObject "$ObjectPath.$requiredProperty" } } foreach ($propertyName in @($ObjectSchema.properties.Keys | Where-Object { $null -ne $_ })) { $propertySchema = $ObjectSchema.properties[$propertyName] $propertyPath = "$ObjectPath.$propertyName" $hasProperty = $SettingsObject.Contains($propertyName) if (-not $hasProperty) { if ($propertySchema.ContainsKey('default')) { $SettingsObject[$propertyName] = $propertySchema.default $hasProperty = $true } elseif ((Get-SchemaTypes -TypeValue $propertySchema.type) -contains 'object' -and $propertySchema.properties) { $hasNestedDefaults = $false foreach ($nestedPropertyName in @($propertySchema.properties.Keys)) { if ($propertySchema.properties[$nestedPropertyName].ContainsKey('default')) { $hasNestedDefaults = $true break } } if ($hasNestedDefaults) { $SettingsObject[$propertyName] = @{} $hasProperty = $true } } } if ($hasProperty) { Test-ValueMatchesSchema -Value $SettingsObject[$propertyName] -ValueSchema $propertySchema -ValuePath $propertyPath } } } Resolve-SettingsObject -SettingsObject $Settings -ObjectSchema $Schema -ObjectPath $SchemaPath $authMode = $Settings.authentication.mode if ($authMode -eq 'clientSecret') { if ([string]::IsNullOrWhiteSpace($Settings.authentication.clientId)) { New-SettingsValidationError -Message "Missing required field for clientSecret authentication: root.authentication.clientId" -ErrorId 'MissingClientId' -Category ([System.Management.Automation.ErrorCategory]::InvalidData) -TargetObject 'root.authentication.clientId' } if ([string]::IsNullOrWhiteSpace($Settings.authentication.clientSecret)) { New-SettingsValidationError -Message "Missing required field for clientSecret authentication: root.authentication.clientSecret" -ErrorId 'MissingClientSecret' -Category ([System.Management.Automation.ErrorCategory]::InvalidData) -TargetObject 'root.authentication.clientSecret' } } return $Settings } |