📄 ui/src/Services/ScanSession.cs
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

namespace Cfa.Ui.Services;

public interface IScanSession : IDisposable
{
    Task<CallGraphAnalysis> AnalyzeAsync(FileInfo file, int line, CancellationToken token);
}

public interface IScanSessionFactory
{
    Task<IScanSession> OpenAsync(FileInfo solution, CancellationToken token);
}

public sealed class ScanSessionFactory : IScanSessionFactory
{
    public async Task<IScanSession> OpenAsync(FileInfo solution, CancellationToken token)
    {
        var options = new ScannerOptions
        {
            Messages = MessageOptions.LoadJson(Path.Combine(solution.DirectoryName!, ".cfa.json"), optional: true),
        };
        var scanner = await Scanner.Create(solution, options, token);
        return new ScanSession(scanner);
    }

    private sealed class ScanSession(Scanner scanner) : IScanSession
    {
        public async Task<CallGraphAnalysis> AnalyzeAsync(FileInfo file, int line, CancellationToken token) =>
            Analyzer.Analyze(await scanner.BuildCallGraph(file, line, token));

        public void Dispose() => scanner.Dispose();
    }
}