Private/Document/Resolve-OpenApiComponentReference.ps1

function Resolve-OpenApiComponentReference {
    <#
    .SYNOPSIS
        Follows $ref chains for parameters, request bodies, responses, headers, security schemes and path items.
    .DESCRIPTION
        Returns { Node, Pointer } for the target (the node itself when it has no $ref), or $null when the
        reference is external (OA020 Error, counted so the operation is flagged Unsupported), cannot be
        resolved or is circular (OA021 Error).
    #>

    [CmdletBinding()]
    [OutputType([pscustomobject])]
    param(
        [Parameter(Mandatory)]
        [pscustomobject]$Context,

        [Parameter(Mandatory)]
        [AllowNull()]
        [object]$Node,

        [Parameter(Mandatory)]
        [AllowEmptyString()]
        [string]$Pointer
    )

    $current = $Node
    $currentPointer = $Pointer
    $seen = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::Ordinal)
    while ($current -is [System.Collections.IDictionary] -and $current.Contains('$ref')) {
        $reference = [string]$current['$ref']
        if (-not $reference.StartsWith('#')) {
            $Context.ExternalRefHits++
            Add-OpenApiFinding -Context $Context -Severity Error -Code 'OA020' -Pointer $currentPointer -Message "External `$ref '$reference' is not supported; the operations that use it are flagged Unsupported."
            return $null
        }
        $target = Resolve-OpenApiPointer -Root $Context.Root -Reference $reference
        if (-not $target.Found) {
            Add-OpenApiFinding -Context $Context -Severity Error -Code 'OA021' -Pointer $currentPointer -Message "`$ref '$reference' could not be resolved."
            return $null
        }
        if (-not $seen.Add($target.Pointer)) {
            Add-OpenApiFinding -Context $Context -Severity Error -Code 'OA021' -Pointer $currentPointer -Message "`$ref '$reference' is circular and could not be resolved."
            return $null
        }
        $current = $target.Value
        $currentPointer = $target.Pointer
    }
    return [pscustomobject]@{ Node = $current; Pointer = $currentPointer }
}