Private/Utils/Set-LinkedFields.ps1
function Set-LinkedFields { <# .SYNOPSIS Populates all linked fields in the result structure (Pass 3). .DESCRIPTION This function fills in all fields that have a Link action. It processes leaf fields, nested objects, and arrays recursively. This is Pass 3 of the three-pass generation process, which runs after all non-linked fields have been populated. .PARAMETER Config The configuration hashtable defining the fields to populate. .PARAMETER Result The result hashtable to populate (already has non-linked fields filled). .PARAMETER ResultContext The result context for resolving linked values (parent scope for arrays). .PARAMETER ParentPath The parent path for error messages (used for recursion). .EXAMPLE Set-LinkedFields -Config $config -Result $result -ResultContext $globalResult Populates all linked fields in the result structure. #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] [hashtable]$Config, [Parameter(Mandatory = $true)] [hashtable]$Result, [Parameter(Mandatory = $true)] [hashtable]$ResultContext, [Parameter(Mandatory = $false)] [string]$ParentPath = "" ) foreach ($key in $Config.Keys) { $fieldConfig = $Config[$key] $currentPath = if ($ParentPath) { "$ParentPath.$key" } else { $key } if ($fieldConfig -is [hashtable]) { if ($fieldConfig.ContainsKey('Type') -and $fieldConfig.Type -eq 'array') { # Array field if ($fieldConfig.ContainsKey('ItemStructure')) { # Array of objects - process each item with the item itself as context $itemConfig = $fieldConfig.ItemStructure for ($i = 0; $i -lt $Result[$key].Count; $i++) { # Pass the array item as the ResultContext so links are resolved within the item Set-LinkedFields -Config $itemConfig -Result $Result[$key][$i] -ResultContext $Result[$key][$i] -ParentPath "$currentPath[$i]" } } # Simple arrays don't have linked fields } elseif ($fieldConfig.ContainsKey('Type')) { # Leaf field - populate if it's a Link action if ($fieldConfig.Action -eq 'Link') { if ($fieldConfig.ContainsKey('LinkTo') -and -not [string]::IsNullOrEmpty($fieldConfig.LinkTo)) { $linkPath = $fieldConfig.LinkTo # Determine context for link resolution # Try to resolve the link in the ResultContext first (for sibling references) $linkedValue = Get-LinkedValue -Result $ResultContext -LinkPath $linkPath # If not found and we're in a nested context, the link might be to a parent field # This is already handled by passing the correct ResultContext during recursion $Result[$key] = $linkedValue Write-Verbose "Set-LinkedFields: Populated linked field '$currentPath' with value='$linkedValue' from LinkTo='$linkPath'" } else { # Missing LinkTo - generate a random value instead Write-Verbose "Field '$currentPath' has Link action but no LinkTo property. Generating random value." # Create a copy of config with Action changed to Randomize to avoid Link processing $randomizeConfig = $fieldConfig.Clone() $randomizeConfig['Action'] = 'Randomize' $Result[$key] = New-ValueFromConfig -FieldConfig $randomizeConfig -SeedValue $null -FieldPath $currentPath -ResultContext $ResultContext } } } else { # Nested object - recurse # Determine correct context by analyzing if linked fields reference local or parent properties $hasLocalLinks = $false foreach ($nestedKey in $fieldConfig.Keys) { $nestedField = $fieldConfig[$nestedKey] if ($nestedField -is [hashtable] -and $nestedField.ContainsKey('Action') -and $nestedField['Action'] -eq 'Link' -and $nestedField.ContainsKey('LinkTo')) { # Check if link target (first segment) exists in nested config $linkTarget = $nestedField['LinkTo'] -split '\.' | Select-Object -First 1 if ($fieldConfig.ContainsKey($linkTarget)) { # Link target is defined in the same config object (local link) $hasLocalLinks = $true Write-Verbose "Set-LinkedFields: Found local link in '$currentPath': '$nestedKey' -> '$linkTarget'" break } } } # If nested config has local links, pass nested result as context # Otherwise pass parent result to allow links to parent's siblings $contextForNested = if ($hasLocalLinks) { $Result[$key] } else { $Result } Write-Verbose "Set-LinkedFields: Nested object '$currentPath', recursing with $(if($hasLocalLinks){'local'}else{'parent'}) context" Set-LinkedFields -Config $fieldConfig -Result $Result[$key] -ResultContext $contextForNested -ParentPath $currentPath } } } } |