Modules/IdLE.Core/Private/Test-IdleCondition.ps1
|
function Test-IdleCondition { [CmdletBinding()] param( [Parameter(Mandatory)] [ValidateNotNull()] [hashtable] $Condition, [Parameter(Mandatory)] [ValidateNotNull()] [object] $Context ) # Evaluates a declarative Condition (data-only) against the provided context. # # Supported schema (validated by Test-IdleConditionSchema): # - Groups: All | Any | None (each contains an array/list of condition nodes) # - Operators: # - Equals = @{ Path = '<path>'; Value = <value> } # - NotEquals = @{ Path = '<path>'; Value = <value> } # - Exists = '<path>' OR @{ Path = '<path>' } # - In = @{ Path = '<path>'; Values = <array|scalar> } # # Paths are resolved via Get-IdleValueByPath against the provided $Context. # For readability in configuration, a leading "context." prefix is ignored. $schemaErrors = Test-IdleConditionSchema -Condition $Condition -StepName $null if (@($schemaErrors).Count -gt 0) { $msg = "Condition schema validation failed: {0}" -f ([string]::Join(' ', @($schemaErrors))) throw [System.ArgumentException]::new($msg, 'Condition') } function Resolve-IdleConditionPathValue { [CmdletBinding()] param( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $Path ) # Allow "context." prefix for readability in config files. $effectivePath = if ($Path.StartsWith('context.')) { $Path.Substring(8) } else { $Path } return Get-IdleValueByPath -Object $Context -Path $effectivePath } function Test-IdleConditionNode { [CmdletBinding()] param( [Parameter(Mandatory)] [ValidateNotNull()] [System.Collections.IDictionary] $Node ) # GROUPS if ($Node.Contains('All')) { foreach ($child in @($Node.All)) { if (-not (Test-IdleConditionNode -Node ([System.Collections.IDictionary]$child))) { return $false } } return $true } if ($Node.Contains('Any')) { foreach ($child in @($Node.Any)) { if (Test-IdleConditionNode -Node ([System.Collections.IDictionary]$child)) { return $true } } return $false } if ($Node.Contains('None')) { foreach ($child in @($Node.None)) { if (Test-IdleConditionNode -Node ([System.Collections.IDictionary]$child)) { return $false } } return $true } # OPERATORS if ($Node.Contains('Equals')) { $op = $Node.Equals $actual = Resolve-IdleConditionPathValue -Path ([string]$op.Path) $expected = $op.Value # Stable semantics: compare as strings (keeps config predictable across providers/types). return ([string]$actual -eq [string]$expected) } if ($Node.Contains('NotEquals')) { $op = $Node.NotEquals $actual = Resolve-IdleConditionPathValue -Path ([string]$op.Path) $expected = $op.Value return ([string]$actual -ne [string]$expected) } if ($Node.Contains('Exists')) { $existsVal = $Node.Exists $path = if ($existsVal -is [string]) { [string]$existsVal } else { [string]$existsVal.Path } $value = Resolve-IdleConditionPathValue -Path $path return ($null -ne $value) } if ($Node.Contains('In')) { $op = $Node.In $actual = Resolve-IdleConditionPathValue -Path ([string]$op.Path) $values = $op.Values if ($null -eq $values) { return $false } # Treat scalar and array uniformly. $candidates = if ($values -is [System.Collections.IEnumerable] -and -not ($values -is [string])) { @($values) } else { @($values) } foreach ($candidate in $candidates) { if ([string]$actual -eq [string]$candidate) { return $true } } return $false } # Should never happen due to schema validation. return $false } return (Test-IdleConditionNode -Node $Condition) } |