Skip to content

Compiler

Edgar Mesquita edited this page Jan 31, 2026 · 10 revisions

The Compiler (CSharpToJs)

The compiler is the core component that enables the magic of eQuantic.UI. It transforms C# semantics into efficient and readable TypeScript code.

🛠️ Compiler Components

1. TypeScriptEmitter

The TypeScriptEmitter is the entry point for generating .ts files. It organizes imports, defines classes, and uses the CSharpToJsConverter to convert method bodies.

2. CSharpToJsConverter

A implementation based on the Strategy pattern that traverses the Roslyn syntax tree (AST).

  • Each type of C# expression or statement has a dedicated strategy (e.g., BinaryExpressionStrategy, IfStatementStrategy).

3. SourceMapGenerator

Generates standard V3 Source Maps with Base64 VLQ encoding, mapping generated JavaScript/TypeScript back to the original .cs or .eqx source lines.

4. Identifier Heuristics

The converter applies intelligent heuristics to decide how to map variable names:

  • C# properties and fields are mapped to this.propertyName in JS.
  • Local variables and parameters retain their original names.
  • System methods like Console.WriteLine are automatically mapped to console.log.

🔄 Supported Strategies

Currently, the compiler supports a wide range of C# constructs:

  • Expressions: Arithmetic, Logical, Ternary, String Interpolation, Null-coalescing (??), Conditional Access (?., ?[])
  • Control Flow: if, switch, for, foreach, while, do-while, break, continue, throw
  • Modern Patterns: Full support for Recursive, Property, Positional, Relational, and Logical patterns (C# 9.0 - 12.0)
  • Resource Management: Support for using statements and using var declarations
  • Exceptions: Full support for try-catch-finally and throw statements (Exception → Error)
  • Indexes and Ranges: Support for index-from-end operator (array[^1]array[array.length - 1])
  • String Methods: Instance methods (Split, Replace, StartsWith, EndsWith, Contains, Substring, IndexOf, LastIndexOf, PadLeft, PadRight, TrimStart, TrimEnd, Insert, Remove, ToCharArray) and static methods (IsNullOrEmpty, IsNullOrWhiteSpace, Join, Concat, Compare, Equals, Format)
  • Number Methods: int.Parse, double.Parse, float.Parse, decimal.Parse, long.Parse, int.TryParse, double.TryParse
  • List Methods: Add, AddRange, Insert, InsertRange, Remove, RemoveAt, RemoveRange, RemoveAll, Clear, IndexOf, LastIndexOf, Find, FindIndex, FindLast, FindLastIndex, FindAll, Exists, TrueForAll, Sort, ForEach, GetRange, CopyTo, BinarySearch
  • Enum Methods: Full enum operations support
    • Enum.Parse<T>(string)parseEnum(value, EnumType) (case-insensitive)
    • Enum.TryParse<T>(string, out var result)(result = parseEnum(value, EnumType), result !== undefined)
    • Enum.GetValues<T>()Object.values(EnumType) - Get all enum values
    • Enum.GetNames<T>()Object.keys(EnumType) - Get all enum member names
    • Enum.IsDefined(typeof(T), value)(EnumType[value] !== undefined) - Validate enum value
  • Dictionary Methods: Complete Dictionary/IDictionary support
    • ContainsKey(key)(key in dict) - Check if key exists
    • TryGetValue(key, out var value)(value = dict[key]) !== undefined - Safe value retrieval
    • Add(key, value)dict[key] = value - Add or update entry
    • Remove(key)delete dict[key] - Remove entry
    • Clear()Object.keys(dict).forEach(k => delete dict[k]) - Remove all entries
    • Keys (property) → Object.keys(dict) - Get all keys as array
    • Values (property) → Object.values(dict) - Get all values as array
  • LINQ: Direct conversion of LINQ methods to JS equivalents:
    • Projection: Selectmap, SelectManyflatMap
    • Filtering: Wherefilter, Distinct[...new Set()]
    • Ordering: OrderBy/OrderByDescendingsort, Reverse[...arr].reverse()
    • Partitioning: Skipslice(n), Takeslice(0, n)
    • Element: First/FirstOrDefaultfind/[0], Last/LastOrDefaultarr[arr.length-1], Single/SingleOrDefaultfind/[0]
    • Quantifiers: Anysome/length > 0, Allevery, Containsincludes
    • Aggregation: Countlength/filter().length, Sumreduce((a,b) => a+b, 0), Averagereduce()/length, MinMath.min(...), MaxMath.max(...)
  • Async/Await: Mapping of Task to Promise and native await support.

📝 Conversion Example

C# Source:

private void Increment() {
    Count++;
    if (Count > 10) Console.WriteLine("Max reached");
}

TypeScript Output:

increment() {
    this.count++;
    if (this.count > 10) console.log("Max reached");
}

🎯 Advanced Features Examples

Enum Operations

C# Source:

public enum OrderStatus { Pending, Processing, Shipped, Delivered }

private void HandleStatusChange(string input)
{
    // Parse enum from string (case-insensitive)
    if (Enum.TryParse<OrderStatus>(input, out var status))
    {
        Console.WriteLine($"Status changed to: {status}");
    }

    // Get all enum values for dropdown
    var allStatuses = Enum.GetValues<OrderStatus>();
    foreach (var s in allStatuses)
    {
        Console.WriteLine($"Available status: {s}");
    }

    // Validate enum value
    if (Enum.IsDefined(typeof(OrderStatus), "Shipped"))
    {
        Console.WriteLine("Valid status");
    }
}

TypeScript Output:

handleStatusChange(input: string) {
    // Parse with TryParse
    if ((status = parseEnum(input, OrderStatus), status !== undefined)) {
        console.log(`Status changed to: ${status}`);
    }

    // Get all values
    const allStatuses = Object.values(OrderStatus);
    for (const s of allStatuses) {
        console.log(`Available status: ${s}`);
    }

    // Validate
    if ((OrderStatus['Shipped'] !== undefined)) {
        console.log('Valid status');
    }
}

Dictionary Operations

C# Source:

private Dictionary<string, int> _settings = new();

private void ManageSettings()
{
    // Add entries
    _settings.Add("timeout", 5000);
    _settings.Add("retries", 3);

    // Check existence
    if (_settings.ContainsKey("timeout"))
    {
        var timeout = _settings["timeout"];
        Console.WriteLine($"Timeout: {timeout}");
    }

    // Safe retrieval
    if (_settings.TryGetValue("maxItems", out var max))
    {
        Console.WriteLine($"Max: {max}");
    }

    // Iterate keys
    foreach (var key in _settings.Keys)
    {
        Console.WriteLine($"{key} = {_settings[key]}");
    }

    // Clear all
    _settings.Clear();
}

TypeScript Output:

private _settings: Record<string, number> = {};

manageSettings() {
    // Add entries
    this._settings['timeout'] = 5000;
    this._settings['retries'] = 3;

    // Check existence
    if (('timeout' in this._settings)) {
        const timeout = this._settings['timeout'];
        console.log(`Timeout: ${timeout}`);
    }

    // Safe retrieval
    if ((max = this._settings['maxItems']) !== undefined) {
        console.log(`Max: ${max}`);
    }

    // Iterate keys
    for (const key of Object.keys(this._settings)) {
        console.log(`${key} = ${this._settings[key]}`);
    }

    // Clear all
    Object.keys(this._settings).forEach(k => delete this._settings[k]);
}

Clone this wiki locally