Modules/businessdev.ALbuild.Apps/Private/Get-BcAlObjectMap.ps1

function Get-BcAlObjectMap {
    <#
    .SYNOPSIS
        Maps AL object identity (type + id) to its source file by scanning a workspace's .al files.
 
    .DESCRIPTION
        Reads the first object declaration in each .al file (e.g. `codeunit 50100 "My Codeunit"`) and
        returns a hashtable keyed "<Type>:<Id>" -> { Type; Id; Name; File }. Used to attach BC code
        coverage rows (which carry only object type + id) to source files. Skips symbol/output/tooling
        folders (relative to the root), like Get-BcProjectBuildOrder.
    #>

    [CmdletBinding()]
    [OutputType([hashtable])]
    param(
        [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $WorkspaceRoot
    )

    $root = (Resolve-Path -LiteralPath $WorkspaceRoot).Path
    $map = @{}
    # First object declaration: <type> <id> <name> ; name may be quoted or bare.
    $rx = [regex]::new(
        '(?im)^\s*(codeunit|table|page|report|xmlport|query|enum|controladdin|pageextension|tableextension|reportextension|enumextension|permissionset|permissionsetextension|profile|interface|entitlement|dotnet)\s+(\d+)\s+("(?<q>[^"]+)"|(?<b>[A-Za-z0-9_]+))')

    foreach ($file in Get-ChildItem -LiteralPath $root -Filter '*.al' -File -Recurse -ErrorAction SilentlyContinue |
            Where-Object { $_.FullName.Substring($root.Length) -notmatch '[\\/](\.alpackages|\.altemplates|\.snapshots|\.output|output|\.git|\.claude|node_modules)[\\/]' }) {
        $text = Get-Content -LiteralPath $file.FullName -Raw -ErrorAction SilentlyContinue
        if (-not $text) { continue }
        $m = $rx.Match($text)
        if (-not $m.Success) { continue }
        $type = (Get-Culture).TextInfo.ToTitleCase($m.Groups[1].Value.ToLowerInvariant())
        $id = [int]$m.Groups[2].Value
        $name = if ($m.Groups['q'].Success) { $m.Groups['q'].Value } else { $m.Groups['b'].Value }
        $map["$type`:$id"] = [PSCustomObject]@{ Type = $type; Id = $id; Name = $name; File = $file.FullName }
    }
    return $map
}