DSL Reference

The Slncs DSL exposes a minimal, fluent surface centered on Solution.Create() and chained builder calls.

Entry Point

using Slncs;
var sol = Solution.Create();

Adding Projects

sol.Project("src/Lib/Lib.csproj")
   .Project("src/App/App.csproj");
  • Paths are treated as relative (recommended). Absolute paths are allowed but reduce portability.
  • Duplicate paths (case-insensitive on Windows) are coalesced.

Adding Folders & Files

sol.Folder("/Solution Items", f =>
{
    f.Files("README.md", "Directory.Build.props")
     .Folder("docs", d => d.File("architecture.md"));
});

Rules:

  • Folder names are normalized to end with / when serialized.
  • Files are included verbatim; no existence check at generation time (MSBuild build phase will surface missing files if relevant).

Chaining & Immutability

The builder mutates internal collections for brevity; it returns this to support chaining. A single terminal call to Write(OutputPath) is standard (where OutputPath is supplied by the scripting host).

Writing Output

sol.Write(OutputPath); // Appends .slnx if absent

OutputPath should point to an .slnx path (the generator passes a path inside obj/).

Advanced Patterns

Conditional Inclusion

var includeSamples = Environment.GetEnvironmentVariable("INCLUDE_SAMPLES") == "1";
if (includeSamples)
    sol.Project("samples/SampleApp/SampleApp.csproj");

Helper Methods for Reuse

static void Backend(SolutionBuilder b)
{
    b.Project("src/Core/Core.csproj")
     .Project("src/Api/Api.csproj");
}

Solution.Create()
    .Folder("/Solution Items", f => f.File("Directory.Build.props"))
    .Also(Backend) // extension method pattern (see below)
    .Write(OutputPath);

Possible extension:

public static class SolutionBuilderExtensions
{
    public static SolutionBuilder Also(this SolutionBuilder b, Action<SolutionBuilder> compose)
    { compose(b); return b; }
}

Dynamic Discovery (Experimental Idea)

Enumerate projects by pattern (manual implementation):

foreach (var csproj in Directory.GetFiles("src", "*.csproj", SearchOption.AllDirectories))
    sol.Project(csproj);

Be cautious: ordering is canonicalized, but discovery cost should be kept low.

Output Schema (.slnx)

<Solution>
  <Folder Name="/Solution Items/">
    <File Path="README.md" />
  </Folder>
  <Project Path="src/Lib/Lib.csproj" />
  <Project Path="src/App/App.csproj" />
</Solution>

No GUIDs, no configurations, no nested solution folder metadata; intentionally lean.

Aggregator Project

Generated as <Output>.slnx.proj (NoTargets). Example:

<Project Sdk="Microsoft.Build.NoTargets/3.6.0">
  <ItemGroup>
    <ProjectReference Include="src/Lib/Lib.csproj" />
    <ProjectReference Include="src/App/App.csproj" />
  </ItemGroup>
</Project>

Deterministic Ordering

Sort precedence: Folders (0), Projects (1), Files (2); then ordinal string ordering. This ensures stable diffs.

Limitations

Area Status
Solution configurations Not supported
Per-project solution nesting GUIDs Not stored
Custom solution-level build events Out of scope
Cross-language project metadata Future RFC

Continue: Tooling & CI