Private/_ALWalker.ps1

function _KriticalLensAlWalkFile {
    <#
    .SYNOPSIS
        Walks a single .al file and emits one row per table reference site,
        each row carrying { File; Line; Column; Table; Kind }.
    #>

    param(
        [Parameter(Mandatory)][string]$Path,
        [string]$RepoRoot
    )
    if (-not (Test-Path -LiteralPath $Path)) { return @() }

    $rows = @()
    $lines = Get-Content -LiteralPath $Path
    for ($i = 0; $i -lt $lines.Count; $i++) {
        $line = $lines[$i]
        # Skip comment-only lines and blank lines for perf.
        if ($line -match '^\s*//') { continue }
        if ([string]::IsNullOrWhiteSpace($line)) { continue }

        foreach ($p in $script:KriticalLensAlPatterns) {
            $ms = [regex]::Matches($line, $p.Regex)
            foreach ($m in $ms) {
                $t = _KriticalLensAlNormalizeTable $m.Groups['t'].Value
                if ([string]::IsNullOrEmpty($t)) { continue }
                # Skip common non-table keywords that survive the pattern
                if ($t -in @('Record','Rec','xRec','var','Object','Codeunit','Page','Table','Report','Query')) { continue }

                $rel = if ($RepoRoot) {
                    try { (Resolve-Path -LiteralPath $Path).Path.Substring((Resolve-Path -LiteralPath $RepoRoot).Path.Length + 1) }
                    catch { $Path }
                } else { $Path }

                $rows += [pscustomobject]@{
                    File   = $rel
                    Line   = $i + 1
                    Column = $m.Index + 1
                    Table  = $t
                    Kind   = $p.Kind
                }
            }
        }
    }
    return $rows
}

function _KriticalLensAlWalkDir {
    <#
    .SYNOPSIS
        Walks every .al file under a directory, emits every table reference.
        Skips .bak.* files, files in .alpackages/, files in archive/.
    #>

    param(
        [Parameter(Mandatory)][string]$Root,
        [string[]]$ExcludeDir = @('.alpackages','archive','_attic','node_modules','.git')
    )

    $files = Get-ChildItem -Path $Root -Recurse -Filter '*.al' -File | Where-Object {
        $keep = $true
        foreach ($ex in $ExcludeDir) {
            if ($_.FullName -like "*$([IO.Path]::DirectorySeparatorChar)$ex$([IO.Path]::DirectorySeparatorChar)*") {
                $keep = $false; break
            }
        }
        $keep -and ($_.Name -notlike '*.bak.*')
    }

    $all = @()
    foreach ($f in $files) {
        $all += _KriticalLensAlWalkFile -Path $f.FullName -RepoRoot $Root
    }
    return $all
}