Skip to content

Carrot.Data.Scaffold.Compilers

net

Core compilation pipeline framework for Carrot's scaffold code generation system. Defines the module/renderer/sink/action abstractions and the orchestrator that drives the build pipeline.

Installation

xml
<ProjectReference Include="..\Carrot.Data.Scaffold.Compilers\Carrot.Data.Scaffold.Compilers.csproj" />

Architecture

Pipeline Flow

ScaffoldCompiler.Build() executes a deterministic pipeline:

  1. StartBuild - fire actions
  2. BeforeModules - fire actions
  3. For each module:
    • Write sink metadata (module-level)
    • For each renderer in the module:
      • renderer.Render() produces IScaffoldCompilerRendererOutput items
      • Write sink metadata (renderer-level, with output counts)
      • Bundle outputs into the manifest
  4. AfterModules - fire actions (bundle is now complete)
  5. For each sink:
    • sink.Write(bundle) - sinks receive the full bundle of outputs
  6. Flush - analyse each manifest directory, detect orphaned files, and delete them
  7. EndBuild - fire actions

Key Abstractions

  • Module (IScaffoldCompilerModule<TGraphRoot>) - owns a graph root (the data model) and a list of renderers. Modules configure their renderers in ConfigureRenderers().
  • Renderer (IScaffoldCompilerRenderer<TGraphRoot, TData>) - transforms graph data into file outputs (IScaffoldCompilerRendererOutput). Output types cover C#, TypeScript, JSON, raw text, Disclose markup, and StringBuilder.
  • Sink (IScaffoldCompilerSink) - writes the bundled outputs somewhere (filesystem, log, etc.). Sinks implementing IScaffoldCompilerSinkMeta also receive per-module/per-renderer metadata callbacks during the module loop.
  • Action (IScaffoldCompilerAction) - cross-cutting logic attached to specific ScaffoldCompilerPipelineEvent points. Actions receive a ScaffoldCompilerActionContext with the current module, renderer, sink, bundle, etc.
  • Manifest (ScaffoldCompilerManifest) - collects all generated files, groups them by directory, and after flush can report new/rewritten/orphaned files via ScaffoldCompilerManifestDirectory.Analyse().

Orphan Detection

During flush, each ScaffoldCompilerManifestDirectory compares existing files on disk with the bundle. Files present on disk but not in the bundle are orphaned and deleted (excluding .csproj, packages.lock.json, readme.md).

Scoped Graph Types

ScaffoldGraphEntityScoped, ScaffoldGraphEnumScoped, and ScaffoldGraphTraitScoped pair a graph element with its owning ScaffoldDatabaseGraphContext, enabling renderers to generate context-aware output.

Dependencies

DependencyKind
Carrot.Data.Scaffoldproject (scaffold data model, graph)
Carrot.IOproject (file path abstractions)
Carrot.Text.Code.CSharpproject (C# code builder)
Carrot.Text.Code.Typescriptproject (TypeScript code builder)
Carrot.Text.Markup.Jsonproject (JSON document builder)

Build

bash
dotnet build

Using Carrot.Data.Scaffold.Compilers

Core compilation pipeline framework - wire up modules, renderers, sinks, and actions to generate code from scaffold data.

Getting Started

csharp
using Carrot.Data.Scaffold.Compilers;
using Carrot.Data.Scaffold.Domain;

scaffold.Compiler(compiler =>
{
    compiler
        .AddModule<MyGraphRoot, MyModule>()
        .SinkTo<MyFileSystemSink>()
        .Build();
});

Common Patterns

1. Define a module with renderers

csharp
public class MyModule : ScaffoldCompilerModule<ScaffoldDatabaseGraph>
{
    public override string Name => "MyModule";

    public override ScaffoldDatabaseGraph GraphRoot => this.Scaffold.ScaffoldDatabase.Graph;

    protected override void ConfigureRenderers()
    {
        this.AddRenderer<MyEntityRenderer, ScaffoldGraphEntityScoped>(
            new ScaffoldGraphEntityScoped(context, entity));
    }
}

2. Define a renderer

csharp
public class MyEntityRenderer : ScaffoldCompilerRenderer<ScaffoldDatabaseGraph, ScaffoldGraphEntityScoped>
{
    public override string Name => "EntityRenderer";

    public override IEnumerable<IScaffoldCompilerRendererOutput> Render()
    {
        CSharpFile file = new("MyEntity.cs");
        // ... build file content from this.Data ...
        yield return new ScaffoldCompilerRendererOutputCSharp(file, "src/Domain/Entities");
    }
}

3. Use renderer options

csharp
public class MyRendererOptions : IScaffoldCompilerRendererOptions
{
    public bool IncludeComments { get; set; } = true;
}

public class MyRenderer : ScaffoldCompilerRenderer<MyGraph, MyData, MyRendererOptions>
{
    public override string Name => "Renderer";

    public override IEnumerable<IScaffoldCompilerRendererOutput> Render()
    {
        if (this.Options.IncludeComments) { /* ... */ }
        // ...
    }
}

4. Register a pipeline action

csharp
compiler.AddAction<MyAction, MyActionOptions>(
    ScaffoldCompilerPipelineEvent.AfterModules,
    options =>
    {
        options.Enabled = true;
    });

5. Register a sink with options

csharp
compiler.SinkTo<MySink, MySinkOptions>(options =>
{
    options.Enabled = true;
    options.DryRun  = false;
});

6. Module with options

csharp
compiler.AddModule<MyGraph, MyModule, MyModuleOptions>(options =>
{
    options.SomeFlag = true;
});

7. Output types

csharp
// C#
yield return new ScaffoldCompilerRendererOutputCSharp(csharpFile, "src/Domain");

// TypeScript
yield return new ScaffoldCompilerRendererOutputTypescript(tsFile, "src/client");

// JSON
yield return new ScaffoldCompilerRendererOutputJson(jsonDoc, "config");

// Raw content
yield return new ScaffoldCompilerRendererOutputRaw(content, "schema", "graphql", "src/api");

// StringBuilder
yield return new ScaffoldCompilerRendererOutputStringBuilder(sb, "output", "txt", "docs");

Tips / Gotchas

  • Actions are sync-over-async - Handle() wraps HandleAsync() via Task.Run().GetAwaiter().GetResult(). Long-running actions should implement HandleAsync properly.
  • Orphan detection ignores .csproj, packages.lock.json, and readme.md - these files are never deleted during flush even if they are not in the bundle.
  • Sinks must opt in - all sinks have IScaffoldCompilerSinkOptions.Enabled. If Enabled is false, IfEnabled() short-circuits and Write/WriteMeta are never called.
  • Module ordering matters - modules execute in registration order, so renderers that depend on files from a previous module should be added after it.
  • Manifest directories are rooted at git root - ScaffoldCompilerManifestBundleItem resolves paths relative to FileSystem.ExecutingAssemblyDirectoryGitRoot.

Package Contents

Carrot.Data.Scaffold.Compilers.Modules.Api

Package: Carrot.Data.Scaffold.Compilers.Modules.Api

Compiler

ScaffoldCompilerApi - scaffold compiler module for the "Api" target; iterates the ScaffoldApi graph and registers renderers for each api, controller, enum, type, command, and model

ScaffoldCompilerApiOptions - options type (currently empty, reserved for future configuration)

Renderers

ScaffoldCompilerApiRendererReadme - generates the root-level readme for the entire API collection (controllers, models, commands, enums, types)

ScaffoldCompilerApiRendererApi - generates the static Api class and rate-limit installation code per API

ScaffoldCompilerApiRendererApiReadme - generates per-API readme files documenting controllers, models, commands, enums, types

ScaffoldCompilerApiRendererController - generates abstract controller base classes with action methods, authorization, search/sort/pagination support, logging, error handling, and security headers

ScaffoldCompilerApiRendererEnum - generates C# enum types from scaffold enum definitions

ScaffoldCompilerApiRendererType - generates C# type classes with constructors, property validation (Ensure* methods), and JSON serialization attributes

ScaffoldCompilerApiRendererCommand - generates C# record types for single-shape command payloads

ScaffoldCompilerApiRendererModel - generates CQRS model records (All, Get, Reference, Create, Update, Upsert, Patch) with primary key resolution, JSON:API resource IDs, and relationship filtering

ScaffoldCompilerApiRendererModelAdapters - generates read/write adapter interfaces and base classes for entity-to-API and API-to-entity CQRS mapping

Extensions

ScaffoldCompilerApiExtensions - IScaffoldCompiler.AddModuleApi() and AddModuleApi(options) extension methods

ScaffoldApiGraphApiExtensions - type resolution helpers: GetTypeName · ResolveActionRequestNameRaw · ResolveActionResponseActionName · ResolveActionResponseImplementationName · ResolveActionResponseNameRaw · ResolveTypeName

CqrsRoleFlagsCSharpExtensions - RenderCSharpExpression() for rendering CqrsRoleFlags as C# code

Exceptions

ScaffoldCompilerApiExceptionTypeNotSupported - thrown when a scaffold type cannot be resolved

ScaffoldCompilerApiExceptionTypeNotSupported<T> - generic variant for strongly-typed context


Carrot.Data.Scaffold.Compilers.Modules.ApiSchemas

Package: Carrot.Data.Scaffold.Compilers.Modules.ApiSchemas

Compiler

ScaffoldCompilerApiSchemas - scaffold compiler module for the "Api Schemas" target; iterates ScaffoldApi graph APIs and registers a Postman collection renderer per API

ScaffoldCompilerApiSchemasOptions - options type (currently empty, reserved for future configuration)

Renderers

ScaffoldCompilerApiSchemasRendererApi - generates a Postman Collection JSON file per API, containing folders per controller with request items for each action, including HTTP verb, URL, headers, and request body property definitions

Extensions

ScaffoldCompilerApiSchemaExtensions - IScaffoldCompiler.AddModuleApiSchemas() and AddModuleApiSchemas(options) extension methods


Carrot.Data.Scaffold.Compilers.Modules.Domain

Package: Carrot.Data.Scaffold.Compilers.Modules.Domain

Compiler

ScaffoldCompilerDomain - scaffold compiler module for the "Domain" target; uses a composite ScaffoldDomain graph root combining both ScaffoldApi and ScaffoldDatabase graphs

ScaffoldCompilerDomainOptions - options type (currently empty, reserved for future configuration)

Graph Root

ScaffoldDomain - composite graph root with Api (ScaffoldApi) and Database (ScaffoldDatabase) properties

Renderers

ScaffoldCompilerDomainRendererReadme - generates the root-level domain readme for the collection

ScaffoldCompilerDomainRendererApiReadme - generates per-API domain readme files

Extensions

ScaffoldCompilerDomainExtensions - IScaffoldCompiler.AddModuleDomain() and AddModuleApi(options) extension methods


Carrot.Data.Scaffold.Compilers.Modules.EntityFramework

Package: Carrot.Data.Scaffold.Compilers.Modules.EntityFramework

Compiler

ScaffoldCompilerEntityFramework - scaffold compiler module for the "EntityFramework" target; iterates the ScaffoldDatabase graph and registers renderers for contexts, entities, repositories, queries, traits, and enums

ScaffoldCompilerEntityFrameworkOptions - options type (currently empty, reserved for future configuration)

Renderers - DbContext

ScaffoldCompilerEntityFrameworkRendererDbContext - generates the DbContext class and its I{ContextName} interface with database/context name properties, entity name/type arrays, and a comparer factory

ScaffoldCompilerEntityFrameworkRendererDbContextDbSets - generates DbSet<T> property declarations

ScaffoldCompilerEntityFrameworkRendererDbContextModelBuilder - generates OnModelCreating with entity configurations, navigations, indexes, and primary keys

ScaffoldCompilerEntityFrameworkRendererDbContextOnConfiguring - generates OnConfiguring overrides

ScaffoldCompilerEntityFrameworkRendererDbContextRegister - generates DI service registration code

ScaffoldCompilerEntityFrameworkRendererDbContextConventions - generates EF model conventions

ScaffoldCompilerEntityFrameworkRendererDbContextConversions - generates EF value conversions for custom types

ScaffoldCompilerEntityFrameworkRendererDbContextReadme - generates per-context readme documentation

Renderers - Entities

ScaffoldCompilerEntityFrameworkRendererEntity - generates entity classes and interfaces with properties, modelling contracts, trait interfaces, and compound key types

ScaffoldCompilerEntityFrameworkRendererRepository - generates repository classes and interfaces with key services, CRUD lifecycle hooks (PrepareForInsert/Update/Delete), and support for CarrotId, compound, and custom key types

ScaffoldCompilerEntityFrameworkRendererQueries - generates query extension classes with Include/ThenInclude methods for navigations, With/For filter methods for foreign keys, and navigation shortcut properties

Renderers - Other

ScaffoldCompilerEntityFrameworkRendererTrait - generates trait interfaces with properties extending ITrait

ScaffoldCompilerEntityFrameworkRendererEnum - generates C# enum types from database enum definitions

ScaffoldCompilerEntityFrameworkRendererInstallation - generates DI installation/registration code per context

ScaffoldCompilerEntityFrameworkRendererReadme - generates the root-level readme

Extensions - EF Naming

ScaffoldGraphEntityExtensions - GetEfName() · GetEfVariable() for entity naming

ScaffoldGraphEntityPropertyExtensions - RenderEf() for property configuration (required, max length, value comparers) · GetTypeNameForContext() for context-aware type resolution

ScaffoldGraphPropertyExtensions - ShouldRender() filter for scalar, enum, and conversion-backed properties

ScaffoldGraphNavigationExtensions - RenderEf() for navigation configuration (HasOne/HasMany, WithOne/WithMany, HasForeignKey, HasConstraintName) · link table support

ScaffoldGraphNavigationShortcutExtensions - RenderEf() for navigation shortcuts (currently a placeholder)

ScaffoldGraphPrimaryKeyExtensions - RenderEf() for primary key and value generation configuration · GetMethodParameters() · RenderProperties()

ScaffoldGraphIndexExtensions - RenderEf() for index configuration (database name, method, operators, unique, clustered) · RenderProperties() · RenderOperators()

ScaffoldGraphTableSchemaExtensions - RenderEfTableSchema() for ToTable() with table name and schema

Extensions - Registration

ScaffoldCompilerEntityFrameworkExtensions - IScaffoldCompiler.AddModuleEntityFramework() and AddModuleEntityFramework(options) extension methods


Carrot.Data.Scaffold.Compilers.Modules.NetClient

Package: Carrot.Data.Scaffold.Compilers.Modules.NetClient

Status

This package is currently an empty placeholder. No public types have been implemented yet.

The project references Carrot.Data.Scaffold.Compilers and contains an empty Data/Scaffold/Graph/ folder, indicating the intended architecture will follow the same scaffold compiler module pattern as the other modules.


Carrot.Data.Scaffold.Compilers.Modules.TypescriptClient

Package: Carrot.Data.Scaffold.Compilers.Modules.TypescriptClient

Compiler

ScaffoldCompilerTypescriptClient - scaffold compiler module for the "TypescriptClient" target; creates directory structures and registers renderers for package root files, source index, endpoints, enums, types, models, and commands per API

ScaffoldCompilerTypescriptClientOptions - options type (currently empty, reserved for future configuration)

Renderers

ScaffoldCompilerTypescriptClientRendererRoot - generates package root files (package.json, tsconfig, etc.) for the generated npm package

ScaffoldCompilerTypescriptClientRendererSrc - generates the src/ directory structure and barrel exports

ScaffoldCompilerTypescriptClientRendererSrcIndex - generates src/index.ts barrel export file

ScaffoldCompilerTypescriptClientRendererSrcEndpoint - generates TypeScript endpoint classes per controller with typed methods for each action

ScaffoldCompilerTypescriptClientRendererSrcEnum - generates TypeScript enum types

ScaffoldCompilerTypescriptClientRendererSrcType - generates TypeScript type/class definitions

ScaffoldCompilerTypescriptClientRendererSrcModel - generates TypeScript model interfaces with CQRS role variants and serializers

ScaffoldCompilerTypescriptClientRendererSrcModel~Serializer - generates model serializer/deserializer functions

ScaffoldCompilerTypescriptClientRendererSrcCommand - generates TypeScript command types

Scoped Types

ScaffoldApiScoped - scoped context carrying FilePath root and ScaffoldApiGraphApi

ScaffoldApiControllerScoped - scoped context for controller rendering (root path, API, controller)

ScaffoldApiEnumScoped - scoped context for enum rendering

ScaffoldApiTypeScoped - scoped context for type rendering

ScaffoldApiModelScoped - scoped context for model rendering

ScaffoldApiCommandScoped - scoped context for command rendering

Graph Extensions

ScaffoldApiGraphApi (in Graph folder) - API graph extensions for TypeScript client generation

Type Extensions

TypescriptTypeExtensions - CLR-to-TypeScript type mapping helpers

Extensions

ScaffoldCompilerTypescriptClientExtensions - IScaffoldCompiler.AddModuleTypescriptClient() and AddModuleTypescriptClient(options) extension methods


Carrot.Data.Scaffold.Compilers.Modules.VueJsLibrary

Package: Carrot.Data.Scaffold.Compilers.Modules.VueJsLibrary

Compiler

ScaffoldCompilerVueJsLibrary - scaffold compiler module for the "VueJsLibrary" target; calculates an ActionMap linking models to Get/Reference controller actions, then registers renderers for package root, source files, and per-model stores

ScaffoldCompilerVueJsLibraryOptions - options type (currently empty, reserved for future configuration)

Renderers

ScaffoldCompilerVueJsLibraryRendererRoot - generates package root files (package.json, tsconfig, etc.)

ScaffoldCompilerVueJsLibraryRendererSrc - generates the src/ directory structure

ScaffoldCompilerVueJsLibraryRendererSrcIndex - generates src/index.ts barrel export

ScaffoldCompilerVueJsLibraryRendererSrcInstall - generates installation/registration entry point

ScaffoldCompilerVueJsLibraryRendererSrcProvide - generates Vue provide/inject setup

ScaffoldCompilerVueJsLibraryRendererSrcUse - generates Vue plugin use composable

ScaffoldCompilerVueJsLibraryRendererSrcStore - generates per-model ApiTypeStore classes with controller action bindings, identity resolvers, reference resolvers, and primary key resolution

ScaffoldCompilerVueJsLibraryRendererSrcStore~ActionBinding - generates action binding methods connecting store actions to API client endpoint calls

ScaffoldCompilerVueJsLibraryRendererSrcStore~Create - generates store factory/creation functions

ScaffoldCompilerVueJsLibraryRendererSrcStore~Install - generates per-store installation code

ScaffoldCompilerVueJsLibraryRendererSrcStore~Use - generates per-store use{Model}Store composable

Scoped Types

ScaffoldApiScoped - scoped context carrying FilePath root, ScaffoldApiGraphApi, and ActionMap

ScaffoldApiModelScoped - scoped context for model store rendering (root path, API, model, actions, controllers)

ScaffoldApiModelIdentityBinding - binding between a model identity and its parameter mappings

ScaffoldApiModelIdentityParameterBinding - maps an identity property name to a controller action parameter

ActionMap - Dictionary<ScaffoldApiGraphModel, IReadOnlyList<ScaffoldApiGraphControllerAction>> mapping models to their Get/Reference actions

Exceptions

ScaffoldApiGraphControllerActionIdentityAmbiguousMatchException - thrown when multiple controller actions ambiguously match a model identity

ScaffoldApiGraphControllerActionIdentityMatchNotFoundException - thrown when no controller action matches a model identity

ScaffoldApiGraphControllerActionMultipleIdentityMatchException - thrown when multiple identities match a single action

Type Extensions

TypescriptTypeExtensions - CLR-to-TypeScript type mapping helpers

Extensions

ScaffoldCompilerVueJsLibraryExtensions - IScaffoldCompiler.AddModuleVueJsLibrary() and AddModuleVueJsLibrary(options) extension methods


Carrot.Data.Scaffold.Compilers.Sinks.FileSystem

Package: Carrot.Data.Scaffold.Compilers.Sinks.FileSystem

Sink

ScaffoldCompilerSinkFileSystem - writes generated code files to disk; creates directories as needed, resolves paths from git root

ScaffoldCompilerSinkFileSystemOptions - options: Enabled (default true) · DryRun (default false)

Extensions

ScaffoldCompilerSinkFileSystemExtensions - IScaffoldCompiler.SinkToFileSystem() · IScaffoldCompiler.SinkToFileSystem(options)


Carrot.Data.Scaffold.Compilers.Sinks.Logging

Package: Carrot.Data.Scaffold.Compilers.Sinks.Logging

Sink

ScaffoldCompilerSinkLog - logging sink with metadata support; reports module execution, renderer completion with file counts, and optionally dumps full file content

ScaffoldCompilerSinkLogOptions - options: Enabled (default true) · ReportFileCreation (default false) · ReportFinalFiles (default false) · ReportZeroFiles (default true)

Extensions

ScaffoldCompilerSinkLogExtensions - IScaffoldCompiler.SinkToLog() · IScaffoldCompiler.SinkToLog(options)


Carrot.Data.Scaffold.Compilers.Actions.EnsureProjects

Package: Carrot.Data.Scaffold.Compilers.Actions.EnsureProjects

Action

ScaffoldCompilerActionEnsureProjects - pipeline action that ensures .NET project structure matches the scaffold graph: creates missing projects, sets root namespaces, adds to solution, manages references

ScaffoldCompilerActionEnsureProjectsOptions - options: Enabled · DryRun · UpdateSolution · FlushFiles · FlushReferences · LogStructure · CommonRoot

Structure

ProjectBuilder - orchestrates project creation, namespace setting, solution management, and reference wiring using a dependency graph

ProjectNode - represents a single project: ProjectName · ProjectFolder · SolutionFolder · Axis · Tier · Ownership · DependsOnProjects · AdditionalReferences · RootNamespace

ProjectNodePaths - resolved paths: Root · ProjectFolderRelative · ProjectFolderAbsolute · ProjectFileRelative · ProjectFileAbsolute

ProjectNodeExtensions - filtering: ByAxis · ByOwnership · ByTier

Enums

ProjectAxis - Domain · Abstraction · Database · Api · Contract · Application · Hosting

ProjectOwnership - Architect · Generated · Implementer — who owns the file contents; drives the build pass (Architect = wire only, Generated = create + wire, Implementer = excluded)

ProjectTier - Base · Collection · Context

Planning

ProjectPlanner - builds the full project graph from scaffold data across all axes: BuildDomain · BuildAbstractions · BuildApi · BuildDatabase · BuildContracts · BuildApplicationApi · BuildApplicationDatabase · BuildApplicationOperations · BuildApplication · BuildHosting

CLI Integration

DotNet - wraps dotnet CLI and Visual Studio tooling: CreateProjectFromTemplateAsync · AddProjectToSolutionAsync · SetProjectRootNamespace · AddReferenceAsync · AddReferencesAsync · RemoveReferencesAsync · GetProjectReferencesAsync · SolutionContainsProjectAsync

Extensions

ScaffoldCompilerActionEnsureProjectsExtensions - IScaffoldCompiler.AddActionEnsureProjects() · IScaffoldCompiler.AddActionEnsureProjects(options)

Carrot