functions/common/Get-FilteredFiles.ps1

function Get-FilteredFiles {
<#
.SYNOPSIS
Filtert eine Liste von Dateien basierend auf einer Exclude-JSON-Datei.
 
.DESCRIPTION
Diese Funktion nimmt eine Liste von Dateien entgegen und entfernt alle Dateien,
die entweder explizit in der `exclude-files.json` aufgeführt sind oder sich in dort
aufgeführten Unterverzeichnissen befinden. Die Einträge in der JSON-Datei müssen
relativ zum Wurzelverzeichnis (`RootPath`) angegeben sein.
 
.PARAMETER Files
Ein Array von `System.IO.FileInfo`-Objekten, das die zu überprüfenden Dateien enthält.
 
.PARAMETER ExcludeListFile
Pfad zur JSON-Datei, die auszuschließende Dateien und Verzeichnisse enthält.
 
.PARAMETER RootPath
Optional: Das Wurzelverzeichnis, relativ zu dem die Ausschlüsse interpretiert werden.
Falls nicht angegeben, wird versucht, es aus den angegebenen Dateien automatisch zu ermitteln.
 
.EXAMPLE
$files = Get-ChildItem -Recurse -File -Path "src"
$filtered = Get-FilteredFiles -Files $files -ExcludeListFile "./exclude-files.json" -RootPath "src"
 
Filtert alle Dateien unterhalb von `src`, die in der JSON-Exclude-Liste stehen.
 
.EXAMPLE
# exclude-files.json
[
    "temp/TestFile.ps1",
    "generated/",
    "legacy/utils/OldFunction.ps1"
]
 
Die Datei `temp/TestFile.ps1` und `legacy/utils/OldFunction.ps1` werden ausgeschlossen.
Zusätzlich wird der gesamte Ordner `generated/` samt Inhalt ignoriert.
 
.OUTPUTS
System.IO.FileInfo[]
 
Eine Liste der übrig gebliebenen Dateien nach Anwendung der Ausschlussregeln.
 
.NOTES
Dateieinträge in der Exclude-Datei verwenden Schrägstriche (`/`) und sind relativ zum `RootPath`.
Ein Schrägstrich am Ende eines Eintrags (`"pfad/zum/ordner/"`) kennzeichnet ein Verzeichnis.
Dateinamen verwenden innerhalb des Skripts intern Backslashes (`\`) für Pfadvergleiche.
#>

    param(
        [Parameter(Mandatory)][System.IO.FileInfo[]] $Files,
        [Parameter(Mandatory)][string] $ExcludeListFile,
        [string] $RootPath = $null
    )

    # Wenn kein RootPath angegeben ist, versuche ihn aus den Files abzuleiten
    if (-not $RootPath) {
        # Einfachster Ansatz: gemeinsamer Root der Dateien finden
        $paths = $Files | ForEach-Object { $_.DirectoryName }
        $RootPath = Get-CommonRootPath -Paths $paths
        if (-not $RootPath) {
            throw "RootPath konnte nicht bestimmt werden. Bitte als Parameter übergeben."
        }
    }
    $RootPath = (Resolve-Path $RootPath).Path.TrimEnd('\','/')

    # Exclude-Liste laden
    $excludeEntries = @()
    if (Test-Path $ExcludeListFile) {
        try {
            $excludeEntries = Get-Content $ExcludeListFile | ConvertFrom-Json
        } catch {
            Write-Warning "Exclude-Datei konnte nicht gelesen werden: $ExcludeListFile"
        }
    }

    # Dateien und Ordner aus der Exclude-Liste trennen
    $excludeFilesRelative = @()
    $excludeDirsRelative = @()
    foreach ($entry in $excludeEntries) {
        if ($entry.EndsWith('/')) {
            $excludeDirsRelative += $entry.TrimEnd('/')
        } else {
            $excludeFilesRelative += $entry -Replace '/', '\'
        }
    }

    # Hilfsfunktion um relativen Pfad zu bekommen
    function Get-RelativePath {
        param (
            [string]$fullPath,
            [string]$basePath
        )

        # Normiere beide Pfade (Backslashes, kein abschließender Slash)
        $normFull = [IO.Path]::GetFullPath($fullPath).TrimEnd('\','/')
        $normBase = [IO.Path]::GetFullPath($basePath).TrimEnd('\','/') + '\'

        if ($normFull.StartsWith($normBase, [System.StringComparison]::OrdinalIgnoreCase)) {
            return $normFull.Substring($normBase.Length)
        } else {
            throw "Pfad '$fullPath' liegt nicht im Basisverzeichnis '$basePath'."
        }
    }

    $filteredFiles = foreach ($file in $Files) {
        # relativer Pfad zur Root (mit Backslashes)
        $relPath = Get-RelativePath -fullPath $file.FullName -basePath $RootPath

        # Prüfe, ob Datei explizit in excludeFiles ist (relativ)
        if ($excludeFilesRelative -contains $relPath) {
            continue
        }

        # Prüfe, ob Datei in einem ausgeschlossenen Verzeichnis liegt
        $inExcludedDir = $false
        foreach ($exDir in $excludeDirsRelative) {
            if ($relPath.StartsWith($exDir + '\')) {
                $inExcludedDir = $true
                break
            }
        }

        if (-not $inExcludedDir) {
            $file
        }
    }

    return $filteredFiles
}