<commit_before>using System;
using System.Collections.Generic;
using System.Linq;
using Bud.Cs;
using Bud.IO;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using static System.IO.Path;
using static System.Reactive.Linq.Observable;
using static Bud.Build;

namespace Bud {
  public static class CSharp {
    public static readonly Key<IObservable<CompileOutput>> Compile = nameof(Compile);
    public static readonly Key<IObservable<CompileInput>> CompilationInput = nameof(CompilationInput);
    public static readonly Key<Func<CompileInput, CompileOutput>> Compiler = nameof(Compiler);
    public static readonly Key<Assemblies> AssemblyReferences = nameof(AssemblyReferences);
    public static readonly Key<string> OutputDir = nameof(OutputDir);
    public static readonly Key<string> AssemblyName = nameof(AssemblyName);
    public static readonly Key<CSharpCompilationOptions> CSharpCompilationOptions = nameof(CSharpCompilationOptions);

    public static Conf CSharpProject(string projectId)
      => CSharpProject(projectId, projectId);

    public static Conf CSharpProject(string projectDir, string projectId)
      => Project(projectDir, projectId)
        .Add(SourceDir(fileFilter: "*.cs"))
        .Add(ExcludeSourceDirs("obj", "bin", "target"))
        .Init(Compile, DefaultCompilation)
        .Init(OutputDir, configs => Combine(ProjectDir[configs], "target"))
        .Init(AssemblyName, configs => ProjectId[configs] + CSharpCompilationOptions[configs].OutputKind.ToExtension())
        .Init(AssemblyReferences, conf => new Assemblies(typeof(object).Assembly.Location))
        .Init(Compiler, TimedEmittingCompiler.Create)
        .InitValue(CSharpCompilationOptions, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary))
        .Init(CompilationInput, DefaultCompilationInput);

    private static void PrintCompilationResult(CompileOutput output) {
      if (output.Success) {
        Console.WriteLine($"Compiled '{GetFileNameWithoutExtension(output.AssemblyPath)}' in {output.CompilationTime.Milliseconds}ms.");
      } else {
        Console.WriteLine($"Failed to compile '{output.AssemblyPath}'.");
        foreach (var diagnostic in output.Diagnostics) {
          Console.WriteLine(diagnostic);
        }
      }
    }

    private static IObservable<CompileOutput> DefaultCompilation(IConf conf)
      => CompilationInput[conf].ObserveOn(BuildPipelineScheduler[conf])
                               .Select(Compiler[conf])
                               .Do(PrintCompilationResult);

    private static IObservable<CompileInput> DefaultCompilationInput(IConf conf)
      => Sources[conf].Watch()
                      .CombineLatest(AssemblyReferences[conf].Watch(),
                                     CollectDependencies(conf),
                                     ToCompilationInput);

    private static IObservable<IEnumerable<CompileOutput>> CollectDependencies(IConf conf)
      => Dependencies[conf].Any() ?
        Dependencies[conf].Select(s => conf.Get(s / Compile)).CombineLatest() :
        Return(Enumerable.Empty<CompileOutput>());

    private static CompileInput ToCompilationInput(IEnumerable<string> files,
                                                   IEnumerable<AssemblyReference> assemblies,
                                                   IEnumerable<CompileOutput> deps)
      => new CompileInput(files, assemblies, deps);
  }
}<commit_msg>Adds a todo note.<commit_after>using System;
using System.Collections.Generic;
using System.Linq;
using Bud.Cs;
using Bud.IO;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using static System.IO.Path;
using static System.Reactive.Linq.Observable;
using static Bud.Build;

namespace Bud {
  public static class CSharp {
    public static readonly Key<IObservable<CompileOutput>> Compile = nameof(Compile);
    public static readonly Key<IObservable<CompileInput>> CompilationInput = nameof(CompilationInput);
    public static readonly Key<Func<CompileInput, CompileOutput>> Compiler = nameof(Compiler);
    public static readonly Key<Assemblies> AssemblyReferences = nameof(AssemblyReferences);
    public static readonly Key<string> OutputDir = nameof(OutputDir);
    public static readonly Key<string> AssemblyName = nameof(AssemblyName);
    public static readonly Key<CSharpCompilationOptions> CSharpCompilationOptions = nameof(CSharpCompilationOptions);

    public static Conf CSharpProject(string projectId)
      => CSharpProject(projectId, projectId);

    public static Conf CSharpProject(string projectDir, string projectId)
      => Project(projectDir, projectId)
        .Add(SourceDir(fileFilter: "*.cs"))
        .Add(ExcludeSourceDirs("obj", "bin", "target"))
        .Init(Compile, DefaultCompilation)
        .Init(OutputDir, configs => Combine(ProjectDir[configs], "target"))
        .Init(AssemblyName, configs => ProjectId[configs] + CSharpCompilationOptions[configs].OutputKind.ToExtension())
        .Init(AssemblyReferences, conf => new Assemblies(typeof(object).Assembly.Location))
        .Init(Compiler, TimedEmittingCompiler.Create)
        .InitValue(CSharpCompilationOptions, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary))
        .Init(CompilationInput, DefaultCompilationInput);

    private static void PrintCompilationResult(CompileOutput output) {
      if (output.Success) {
        Console.WriteLine($"Compiled '{GetFileNameWithoutExtension(output.AssemblyPath)}' in {output.CompilationTime.Milliseconds}ms.");
      } else {
        Console.WriteLine($"Failed to compile '{output.AssemblyPath}'.");
        foreach (var diagnostic in output.Diagnostics) {
          Console.WriteLine(diagnostic);
        }
      }
    }

    private static IObservable<CompileOutput> DefaultCompilation(IConf conf)
      => CompilationInput[conf].ObserveOn(BuildPipelineScheduler[conf])
                               .Select(Compiler[conf])
                               .Do(PrintCompilationResult);

    // TODO: File watchers are triggering duplicate updates in bursts. Throttle them.
    private static IObservable<CompileInput> DefaultCompilationInput(IConf conf)
      => Sources[conf].Watch()
                      .CombineLatest(AssemblyReferences[conf].Watch(),
                                     CollectDependencies(conf),
                                     ToCompilationInput);

    private static IObservable<IEnumerable<CompileOutput>> CollectDependencies(IConf conf)
      => Dependencies[conf].Any() ?
        Dependencies[conf].Select(s => conf.Get(s / Compile)).CombineLatest() :
        Return(Enumerable.Empty<CompileOutput>());

    private static CompileInput ToCompilationInput(IEnumerable<string> files,
                                                   IEnumerable<AssemblyReference> assemblies,
                                                   IEnumerable<CompileOutput> deps)
      => new CompileInput(files, assemblies, deps);
  }
}
{'fraction_non_alphanumeric': 0.09612625538020086, 'fraction_numerical': 0.0, 'mean_word_length': 3.414819506016466, 'pattern_counts': {'":': 0, '<': 39, '<?xml version=': 0, '>': 59, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5343292', 'n_tokens_mistral': 1807, 'n_tokens_neox': 1718, 'n_words': 366}