A TypeScript-to-C# migration verification toolkit. Parse TypeScript and C# files into ASTs, then compare them to validate that your C# migration faithfully preserves the structure and signatures of the original TypeScript code.
- Sigsegv.TypeScriptToCsharp.Ast - Core C# library for parsing and comparing ASTs
TypeScriptParser- Parses TypeScript files via a Node.js script using the TypeScript compiler APICSharpParser- Parses C# files using RoslynAstComparer- Compares TypeScript and C# ASTs with configurable naming convention mapping
- ts-parser.js - Node.js script that extracts AST information from TypeScript files
- MigrationTestBase - xUnit test base class for writing migration validation tests
- PowerShell scripts - Generate test fixtures from TypeScript files
- Claude skill - AI-assisted TypeScript-to-C# conversion following best practices
- .NET 10 SDK
- Node.js (for TypeScript parsing)
- TypeScript npm package (
npm install -g typescript)
To use this the main power is in the SimilarityScore mentioned below when comparing two files, which is a number from 0.0-1.0 which indicates how similar the two ASTs between two versions (.ts and .cs) are. You can tune this and run it in a verification loop as follows:
- generate a C# test fixture using
scripts/Generate-TestFixture.ps1 - use the skill at
.claude/skills/ts-to-csharpto convert yourtsfile tocs, or use your own instructions for however you want to perform the migration - run the tests, paying attention to anything that did not migrate cleanly or anything that was hallucinated. In particular, you can pay attention to the
SimilarityScore - if the two files are similar enough, continue to the next file, otherwise go back to step 2
var tsParser = new TypeScriptParser();
var tsFile = await tsParser.ParseFileAsync("path/to/file.ts");
foreach (var cls in tsFile.Classes)
{
Console.WriteLine($"Class: {cls.Name}");
foreach (var method in cls.Methods)
{
Console.WriteLine($" Method: {method.Name}({string.Join(", ", method.Parameters.Select(p => $"{p.Name}: {p.Type}"))})");
}
}var csParser = new CSharpParser();
var csFile = csParser.ParseFile("path/to/File.cs");
foreach (var cls in csFile.Classes)
{
Console.WriteLine($"Class: {cls.Name} ({cls.AccessModifier})");
foreach (var method in cls.Methods)
{
Console.WriteLine($" Method: {method.Name} -> {method.ReturnType}");
}
}var tsParser = new TypeScriptParser();
var csParser = new CSharpParser();
var comparer = new AstComparer();
var tsFile = await tsParser.ParseFileAsync("path/to/file.ts");
var csFile = csParser.ParseFile("path/to/File.cs");
var result = comparer.Compare(tsFile, csFile);
Console.WriteLine($"Match: {result.IsMatch}");
Console.WriteLine($"Similarity: {result.SimilarityScore:P0}");
foreach (var issue in result.Issues)
{
Console.WriteLine($"[{issue.Severity}] {issue.Message}");
}Create a test class that extends MigrationTestBase:
using Sigsegv.TypeScriptToCsharp.Ast.Tests;
public class BattleMigrationTests : MigrationTestBase
{
protected override string TypeScriptRelativePath => "src/server/system/battle.ts";
// Optional: override if C# file is in a non-default location
protected override string CSharpRelativePath => "src/Server/System/Battle.cs";
[Fact]
public void StructurallyMatches()
{
AssertStructuralMatch();
}
[Fact]
public void AllMethodSignaturesMatch()
{
AssertAllMethodSignaturesMatch("Battle");
}
[Fact]
public void BattleClassMatches()
{
var classComparison = AssertClassMatches("Battle");
classComparison.SimilarityScore.Should().BeGreaterOrEqualTo(0.8);
}
}Use the PowerShell scripts to auto-generate test fixtures:
# Generate a simple test fixture
pwsh scripts/Generate-TestFixture.ps1 src/server/system/battle.ts
# Generate a migration test fixture (uses MigrationTestBase)
pwsh scripts/Generate-MigrationTestFixture.ps1 src/server/system/battle.tsdotnet build Sigsegv.TypeScriptToCsharp.slndotnet test Sigsegv.TypeScriptToCsharp.sln-
TypeScript parsing: The
ts-parser.jsNode.js script uses the TypeScript compiler API to extract classes, interfaces, methods, properties, enums, and functions from.tsfiles, outputting a JSON AST. -
C# parsing: The
CSharpParseruses Roslyn (Microsoft.CodeAnalysis.CSharp) to parse.csfiles into a matching AST model. -
Comparison: The
AstComparerwalks both ASTs simultaneously, comparing:- Class/interface/enum existence and structure
- Method signatures (name, parameters, return type)
- Property types and accessors
- Method body structure similarity
- Naming conventions (camelCase to PascalCase mapping)
-
Reporting: Comparison results include match status, similarity scores, and detailed issues categorized by severity.
The .claude/skills/ts-to-csharp/SKILL.md file contains a Claude skill for AI-assisted TypeScript-to-C# conversion. When used with Claude Code, it provides automated conversion following the naming conventions, type mappings, and structural patterns defined in the skill.
Sigsegv.TypeScriptToCsharp/
├── src/Sigsegv.TypeScriptToCsharp.Ast/ # Core AST library
│ ├── CSharpParser.cs # Roslyn-based C# parser
│ ├── TypeScriptParser.cs # Node.js-based TS parser
│ ├── Comparison/ # AST comparison engine
│ ├── Models/ # TypeScript AST models
│ ├── Models/CSharp/ # C# AST models
│ └── Scripts/ts-parser.js # Node.js TS parser script
├── test/Sigsegv.TypeScriptToCsharp.Ast.Tests/ # Tests
│ ├── AstComparerTests.cs
│ ├── CSharpParserTests.cs
│ └── Infrastructure/MigrationTestBase.cs
├── scripts/ # PowerShell test generators
└── .claude/skills/ts-to-csharp/ # Claude AI skill
MIT