Mirrorgen.MSBuild 0.4.3

dotnet add package Mirrorgen.MSBuild --version 0.4.3
                    
NuGet\Install-Package Mirrorgen.MSBuild -Version 0.4.3
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Mirrorgen.MSBuild" Version="0.4.3">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Mirrorgen.MSBuild" Version="0.4.3" />
                    
Directory.Packages.props
<PackageReference Include="Mirrorgen.MSBuild">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Mirrorgen.MSBuild --version 0.4.3
                    
#r "nuget: Mirrorgen.MSBuild, 0.4.3"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Mirrorgen.MSBuild@0.4.3
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Mirrorgen.MSBuild&version=0.4.3
                    
Install as a Cake Addin
#tool nuget:?package=Mirrorgen.MSBuild&version=0.4.3
                    
Install as a Cake Tool

Mirrorgen

English · 한국어

Transpile C# types and pure logic into TypeScript — with cross-validation that proves the two stay in lockstep.

Existing C#-to-TypeScript generators stop at type shape: enums, records, DTO interfaces. That leaves logic mirrors — validation rules, pricing and tax math, permission checks, compact wire-format codecs — duplicated by hand on both sides of the JS/.NET boundary. Mirrorgen targets the half that's actually expensive to maintain.

// C# (source of truth)
[Transpile]
public static bool IsWithinDistance(int x1, int y1, int x2, int y2, int radius)
{
    var dx = x2 - x1;
    var dy = y2 - y1;
    return dx * dx + dy * dy <= radius * radius;
}
// _generated/rules.ts — emitted at build time
export function isWithinDistance(x1: number, y1: number, x2: number, y2: number, radius: number): boolean {
    const dx = (x2 - x1) | 0;
    const dy = (y2 - y1) | 0;
    return Math.imul(dx, dx) + Math.imul(dy, dy) <= Math.imul(radius, radius);
}

And the part nobody else does — Mirrorgen emits a fixture cross-test: C# generates random inputs and expected outputs at build time, the TypeScript test consumes the same fixture, and CI fails the moment the two implementations diverge by a single bit.

Why

Any project with a .NET backend (ASP.NET, SignalR, Blazor Server, a custom simulation) plus a TypeScript client ends up maintaining two copies of the same logic — and the cost is silent drift, not duplication itself. A constant changes on one side, the other forgets, a bug ships. Existing tools can't help because they only mirror data shape.

Mirrorgen exists to make logic mirrors as cheap as type mirrors:

  • One source of truth: C#
  • One opt-in marker: [Transpile]
  • Generated TypeScript ships next to the consuming code
  • Cross-validation fixtures keep the two byte-exact, forever

Where Mirrorgen fits

Existing tools cluster into two groups: type-only generators that mirror DTO shape but not logic (TypeGen, Tapper, Reinforced.Typings, NSwag), and full-app C# → JS compilers that let you write the whole client in C# at the cost of a substantial in-browser runtime (Bridge.NET, H5, JSIL, Blazor WASM). F# teams have Fable for the equivalent F# → TS story. Mirrorgen targets the gap: plain .ts output that mirrors selected C# logic alongside a hand-written TypeScript client.

Mirrorgen Type-only generators Full-app C# → JS Fable (F# → TS)
C# logic body narrow subset full C# n/a (F#)
Output TypeScript TypeScript JavaScript TypeScript or JS
Client runtime cost KB (tiny helper) none hundreds of KB+ varies
Cross-validation fixtures
Subset-enforcing analyzer n/a n/a
Use model mirror logic next to hand-written TS mirror DTOs write whole client in C# write whole client in F#

If you want to write your whole client in C# or F#, use H5 / Blazor WASM / Fable. If you only need DTO shapes mirrored, TypeGen or Tapper is smaller and battle-tested. Mirrorgen exists because hand-mirroring rules / pricing / validation / codecs while keeping them in lockstep with C# is what burns time, and none of those columns targets it. The closest C# → TS method transpiler attempt (Rosetta by andry-tino) is explicitly dead in its README; lessons from why it stalled inform Mirrorgen's design and are written up in docs/CONCEPT.md.

What it doesn't do (on purpose)

Mirrorgen is a subset transpiler. It does not try to translate arbitrary C#. The supported subset is intentionally narrow so the output stays predictable, debuggable, and byte-exact:

  • async / await, Task, threading
  • ❌ LINQ, deferred enumerables
  • Span<T>, ref, unsafe, pointers
  • ❌ Exceptions (return result types instead)
  • ❌ Reflection
  • ❌ Inheritance and virtual dispatch

A Roslyn analyzer marks any [Transpile] member that crosses these lines as a build error — you find out in your IDE, not at codegen time.

See docs/CONCEPT.md for the precise subset spec and roadmap.

Status

v0.3.1 — published on NuGet (all five packages). The walker subset is feature-complete, plugin discovery works end-to-end, and the cross-validation harness keeps the C# and TS sides byte-equivalent on every push. The API may still shift while early adopters shake it out.

Watch / star to be pinged on new releases.

How it will fit into a project


<ItemGroup>
    <PackageReference Include="Mirrorgen.Attributes" Version="0.3.1" />
    <PackageReference Include="Mirrorgen.Analyzers" Version="0.3.1" PrivateAssets="all" />
    <PackageReference Include="Mirrorgen.MSBuild" Version="0.3.1" PrivateAssets="all" />
</ItemGroup>

<PropertyGroup>
    <MirrorgenOutput>$(MSBuildThisFileDirectory)../YourProject.Client/src/_generated/</MirrorgenOutput>
    <MirrorgenConfig>YourProject.MirrorgenConfig</MirrorgenConfig>
</PropertyGroup>
// Domain type mapping plugin
public sealed class MirrorgenConfig : IMirrorgenExtension
{
    public void Configure(IMirrorgenBuilder b)
    {
        b.MapType<OrderId>().AsPrimitive("number");
        b.MapType<Money>().RuntimeImport("Money");
    }
}

The TypeScript side gets a tiny runtime helper package (@mirrorgen/runtime) for integer arithmetic, equality, and pluggable domain helpers — kept under a few KB so the generated code stays clean.

License

MIT.

Repository layout

mirrorgen/
  src/
    Mirrorgen.Core/         # Roslyn-based transpiler engine
    Mirrorgen.Attributes/   # [Transpile], [GenerateCrossTest] — zero-dep, ref'd by users
    Mirrorgen.Analyzers/    # Roslyn analyzer enforcing the subset
    Mirrorgen.MSBuild/      # MSBuild target wrapper
    Mirrorgen.Cli/          # `dotnet mirrorgen` tool
  runtime-ts/               # @mirrorgen/runtime npm package
    cross/                  # checked-in TS emit + fixture JSON for cross-validation
  cross-fixtures/           # C# subject methods consumed by the cross-validation flow
  scripts/
    regen-cross.sh          # rebuilds runtime-ts/cross/{subject.ts,subject.fixtures.json}
  samples/
    minimal/                # smallest possible C# -> TS example
    pricing-rules/          # non-trivial sample with domain-type mapping
  tests/
    Mirrorgen.Tests/        # walker / operator / fixture-generator unit tests
  docs/
    CONCEPT.md              # this is where the design lives
    SUBSET.md               # exact subset spec
    ROADMAP.md
There are no supported framework assets in this package.

Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.4.3 75 6/4/2026
0.4.2 51 6/4/2026
0.4.1 55 6/4/2026
0.4.0 57 6/4/2026
0.3.1 250 5/28/2026
0.3.0 95 5/28/2026
0.3.0-alpha.44 50 5/28/2026
0.3.0-alpha.43 47 5/28/2026
0.3.0-alpha.42 47 5/28/2026
0.3.0-alpha.41 43 5/28/2026
0.3.0-alpha.40 46 5/28/2026
0.3.0-alpha.39 42 5/28/2026
0.3.0-alpha.38 49 5/28/2026
0.3.0-alpha.37 48 5/28/2026
0.3.0-alpha.36 54 5/28/2026
0.3.0-alpha.35 51 5/28/2026
0.3.0-alpha.34 62 5/28/2026
0.3.0-alpha.33 66 5/28/2026
0.3.0-alpha.32 54 5/28/2026
0.3.0-alpha.31 51 5/28/2026
Loading failed