Modules/businessdev.ALbuild.Apps/Public/Resolve-BcAnalyzerConfig.ps1

function Resolve-BcAnalyzerConfig {
    <#
    .SYNOPSIS
        Determines the code analyzers and ruleset for a compile, layering the sources by precedence.
 
    .DESCRIPTION
        Precedence (highest first): an explicit value (the task input) > the project's albuild.json
        (Analyzers / RuleSet) > the project's .vscode/settings.json ('al.codeAnalyzers' /
        'al.ruleSetPath'). Only the highest source that supplies a value is used (the sources do not
        merge), matching how an explicit pipeline input overrides committed config. Analyzer entries
        are returned as given (tokens / short names / DLL paths - Resolve-BcAnalyzer maps them at
        compile time); a relative ruleset path is resolved against the project folder.
 
    .PARAMETER ProjectFolder
        The AL project folder (holds app.json, optionally .vscode/settings.json and albuild.json).
 
    .PARAMETER WorkspaceRoot
        Workspace root for albuild.json resolution (merged root + app). Default: the project folder.
 
    .PARAMETER InputAnalyzers
        Explicit analyzers from the task input (comma/semicolon separated). Wins over config.
 
    .PARAMETER InputRuleSet
        Explicit ruleset path from the task input. Wins over config.
 
    .OUTPUTS
        PSCustomObject: Analyzers (string[]), RuleSet (string), AnalyzersSource, RuleSetSource.
    #>

    [CmdletBinding()]
    [OutputType([PSCustomObject])]
    param(
        [Parameter(Mandatory)] [string] $ProjectFolder,
        [string] $WorkspaceRoot,
        [string] $InputAnalyzers,
        [string] $InputRuleSet
    )

    if (-not $WorkspaceRoot) { $WorkspaceRoot = $ProjectFolder }

    # albuild.json (Analyzers / RuleSet)
    $cfgAnalyzers = @(); $cfgRuleSet = ''
    try {
        $cfg = Get-ALbuildProjectConfig -AppFolder $ProjectFolder -WorkspaceRoot $WorkspaceRoot
        if ($cfg) {
            if ($cfg.Analyzers) { $cfgAnalyzers = @($cfg.Analyzers) }
            if ($cfg.RuleSet) { $cfgRuleSet = [string] $cfg.RuleSet }
        }
    }
    catch { Write-Verbose "No albuild.json analyzer config at '$ProjectFolder': $($_.Exception.Message)" }

    # .vscode/settings.json (al.codeAnalyzers / al.ruleSetPath)
    $setAnalyzers = @(); $setRuleSet = ''
    $settingsPath = Join-Path $ProjectFolder '.vscode/settings.json'
    if (Test-Path -LiteralPath $settingsPath) {
        try {
            $raw = Get-Content -LiteralPath $settingsPath -Raw
            # VS Code settings allow // line comments (JSONC); strip whole-line comments conservatively.
            $clean = (($raw -split "`n") | ForEach-Object { $_ -replace '^\s*//.*$', '' }) -join "`n"
            $settings = $clean | ConvertFrom-Json
            if ($settings.'al.codeAnalyzers') { $setAnalyzers = @($settings.'al.codeAnalyzers') }
            if ($settings.'al.ruleSetPath') { $setRuleSet = [string] $settings.'al.ruleSetPath' }
        }
        catch { Write-Verbose "Could not read analyzers from '$settingsPath': $($_.Exception.Message)" }
    }

    # Precedence: task input > albuild.json > settings.json.
    $analyzers = @(); $aSource = 'none'
    if (-not [string]::IsNullOrWhiteSpace($InputAnalyzers)) {
        $analyzers = @($InputAnalyzers -split '[;,]' | ForEach-Object { $_.Trim() } | Where-Object { $_ })
        $aSource = 'task input'
    }
    elseif ($cfgAnalyzers.Count -gt 0) { $analyzers = $cfgAnalyzers; $aSource = 'albuild.json' }
    elseif ($setAnalyzers.Count -gt 0) { $analyzers = $setAnalyzers; $aSource = '.vscode/settings.json' }

    $rawRule = ''; $rSource = 'none'
    if (-not [string]::IsNullOrWhiteSpace($InputRuleSet)) { $rawRule = $InputRuleSet; $rSource = 'task input' }
    elseif ($cfgRuleSet) { $rawRule = $cfgRuleSet; $rSource = 'albuild.json' }
    elseif ($setRuleSet) { $rawRule = $setRuleSet; $rSource = '.vscode/settings.json' }

    $ruleset = ''
    if ($rawRule) {
        $ruleset = if ([System.IO.Path]::IsPathRooted($rawRule)) { $rawRule } else { Join-Path $ProjectFolder $rawRule }
    }

    return [PSCustomObject]@{
        Analyzers       = @($analyzers)
        RuleSet         = $ruleset
        AnalyzersSource = $aSource
        RuleSetSource   = $rSource
    }
}