Core/Private/Filtering/Get-TreeItemFilterStatus.ps1
|
# src/Private/Filtering/Get-TreeItemFilterStatus.ps1 <# .SYNOPSIS Determines the filtering status of an item. .DESCRIPTION Get-TreeItemFilterStatus evaluates an item against sets of Include and Exclude patterns. It returns a status of 'Included', 'Excluded', 'Ancestor' (if the item is a required structural parent for a nested inclusion), or 'Default'. #> function Get-TreeItemFilterStatus { param( [object]$Item, [string[]]$Include, [string[]]$Exclude, [string]$RootPath ) if (-not $PSBoundParameters.ContainsKey('Debug') -and $PSCmdlet) { $DebugPreference = $PSCmdlet.GetVariableValue('DebugPreference') } if (-not $PSBoundParameters.ContainsKey('Verbose') -and $PSCmdlet) { $VerbosePreference = $PSCmdlet.GetVariableValue('VerbosePreference') } $name = $Item.Name $itemFullPath = [System.IO.Path]::GetFullPath($Item.FullPath).TrimEnd([System.IO.Path]::DirectorySeparatorChar) Write-Verbose "Checking Item: $name ($itemFullPath)" # 1. Evaluate Exclusions $isExcludedByName = $Exclude -contains $name -or $Exclude -contains "$name$([System.IO.Path]::DirectorySeparatorChar)" $isExcludedByPath = $false if ($Exclude) { foreach ($pattern in $Exclude) { if (Test-TreeItemFilterMatch -Item $Item -Pattern $pattern -RootPath $RootPath) { Write-Verbose " Excluded by Name: $name" $isExcludedByPath = $true break } } } # 2. Evaluate Inclusions $isDirectlyIncluded = $false if ($Include) { foreach ($pattern in $Include) { # When checking inclusions, we do NOT provide RootPath to Test-TreeItemFilterMatch # to prevent broad name-only inclusions from matching every child in the tree. if (Test-TreeItemFilterMatch -Item $Item -Pattern $pattern -RootPath $RootPath) { Write-Verbose " Included by pattern: $pattern" $isDirectlyIncluded = $true break } } } # 3. Rescue Check (Structural Visibility for ancestors) $isAncestorOfInclusion = $false if ($Include) { foreach ($pattern in $Include) { if ($Item.IsContainer) { $filter = ConvertTo-TreeFilterPattern -Pattern $pattern -RootPath $RootPath # If the pattern contains separators, use efficient prefix matching $isPathPattern = $pattern.Contains([System.IO.Path]::DirectorySeparatorChar) -or $pattern.Contains('/') Write-Verbose " Rescue Check pattern: '$($filter.Pattern)' (IsPath: $isPathPattern)" if ($isPathPattern) { $patternPath = $filter.Pattern if (-not [System.IO.Path]::IsPathRooted($patternPath)) { $base = [string]::IsNullOrWhiteSpace($RootPath) ? $PWD.ProviderPath : $RootPath $patternPath = [System.IO.Path]::Combine($base, $patternPath) } # Normalize for consistent prefix matching $patternPath = $patternPath.TrimEnd([System.IO.Path]::DirectorySeparatorChar) # Check if current item is a parent of the inclusion path $itemPrefix = $itemFullPath + [System.IO.Path]::DirectorySeparatorChar Write-Verbose " Prefix Check: itemPrefix='$itemPrefix' vs patternPath='$patternPath'" if ($patternPath.StartsWith($itemPrefix, [System.StringComparison]::OrdinalIgnoreCase)) { Write-Verbose " Ancestor Rescue (Prefix): Item matches prefix of $patternPath" $isAncestorOfInclusion = $true break } # Exact parent check $parentPath = [System.IO.Path]::GetDirectoryName($patternPath) if ($parentPath -and $itemFullPath -eq $parentPath.TrimEnd([System.IO.Path]::DirectorySeparatorChar)) { Write-Verbose " Ancestor Rescue (Parent): Item is parent of $patternPath" $isAncestorOfInclusion = $true break } } else { Write-Verbose " Falling back to Test-Path matching for name pattern: $pattern" # Use Test-Path to see if the inclusion exists anywhere inside the current item if (Test-Path -LiteralPath (Join-Path $Item.FullPath $pattern) -ErrorAction SilentlyContinue) { Write-Verbose " True" $isAncestorOfInclusion = $true break } Write-Verbose " False" } } } } # Priority: Ancestor > ExcludedByName > Included > ExcludedByPath > Default if ($isAncestorOfInclusion) { return 'Ancestor' } if ($isExcludedByName) { return 'Excluded' } if ($isDirectlyIncluded) { return 'Included' } if ($isExcludedByPath) { return 'Excluded' } return 'Default' } |