private/Reconstruct-Object.ps1

function Reconstruct-Object {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)][string]$DirPath,
        [int]$Depth = [int]::MaxValue,
        [int]$CurrentDepth = 0,
        [System.Collections.Generic.HashSet[string]]$Visited
    )

    $di = [System.IO.DirectoryInfo]::new($DirPath)
    if (-not $di.Exists) { return $null }

    if ($null -eq $Visited) { $Visited = [System.Collections.Generic.HashSet[string]]::new() }
    $dirResolved = [System.IO.Path]::GetFullPath($(if ($null -ne $di.LinkTarget) { $di.LinkTarget } else { $di.FullName }))
    if ($Visited.Contains($dirResolved)) { return $null }
    $null = $Visited.Add($dirResolved)

    $props = [ordered]@{}
    $allNumeric = $true
    $hasEntries = $false

    $allFiles = @($di.GetFiles("*.json")) + @($di.GetFiles("*.dat"))
    foreach ($file in $allFiles) {
        $hasEntries = $true
        $key = [System.IO.Path]::GetFileNameWithoutExtension($file.Name)
        if ($key -notmatch '^\d+$') { $allNumeric = $false; break }
    }

    if ($allNumeric) {
        foreach ($subDir in $di.GetDirectories()) {
            if ($subDir.Name -eq '.buckets') { continue }
            $hasEntries = $true
            if ($subDir.Name -notmatch '^\d+$') { $allNumeric = $false; break }
        }
    }

    if (-not $hasEntries) { return $null }

    if ($allNumeric) {
        $items = @{}
        foreach ($file in $allFiles) {
            $idx = [int][System.IO.Path]::GetFileNameWithoutExtension($file.Name)
            $value = Read-BucketFile -File $file
            if ($null -ne $value) { $items[$idx] = $value }
        }
        if ($CurrentDepth -lt $Depth) {
            foreach ($subDir in $di.GetDirectories()) {
                if ($subDir.Name -eq '.buckets') { continue }
                $idx = [int]$subDir.Name
                $items[$idx] = Reconstruct-Object -DirPath $subDir.FullName -Depth $Depth -CurrentDepth ($CurrentDepth + 1) -Visited $Visited
            }
        }
        if ($items.Count -eq 0) { return $null }
        $sorted = $items.Keys | Sort-Object
        return [System.Collections.ArrayList]@($sorted | ForEach-Object { $items[$_] })
    }
    else {
        $result = [ordered]@{}
        foreach ($file in $allFiles) {
            $key = [System.IO.Path]::GetFileNameWithoutExtension($file.Name)
            $value = Read-BucketFile -File $file
            if ($null -ne $value) { $result[$key] = $value }
        }
        if ($CurrentDepth -lt $Depth) {
            foreach ($subDir in $di.GetDirectories()) {
                if ($subDir.Name -eq '.buckets') { continue }
                $result[$subDir.Name] = Reconstruct-Object -DirPath $subDir.FullName -Depth $Depth -CurrentDepth ($CurrentDepth + 1) -Visited $Visited
            }
        }
        if ($result.Count -eq 0) { return $null }
        return [PSCustomObject]$result
    }
}