Renaming System
The renaming system manages all TypeScript identifier generation.
SymbolRenamer
File: Renaming/SymbolRenamer.cs
Central naming authority:
public sealed class SymbolRenamer
{
// Style transforms
public void AdoptTypeStyleTransform(Func<string, string> transform);
public void AdoptMemberStyleTransform(Func<string, string> transform);
// Reservation
public void ReserveTypeName(StableId id, string requested, RenameScope scope, ...);
public void ReserveMemberName(StableId id, string requested, RenameScope scope, ...);
// Querying
public string GetFinalTypeName(TypeSymbol type);
public string GetInstanceTypeName(TypeSymbol type); // T$instance
public string GetStaticInterfaceName(TypeSymbol type); // T$static
public string GetFinalMemberName(StableId id, RenameScope scope);
}
Scopes
File: Renaming/RenameScope.cs
Names are reserved within scopes:
public abstract record RenameScope(string ScopeKey);
public sealed record NamespaceScope(
string NamespaceName,
NamespaceArea Area // Internal or Facade
) : RenameScope($"ns:{NamespaceName}#{Area}");
public sealed record TypeScope(
string TypeClrName,
bool IsStatic,
bool IsView,
string? ViewInterfaceId
) : RenameScope(...);
Scope examples:
ns:System.Collections.Generic#internal- Namespace scopetype:System.Collections.Generic.List\1#instance` - Instance memberstype:System.Collections.Generic.List\1#static` - Static membersview:System.Collections.Generic.List\1:IEnumerable`1#instance` - View members
ScopeFactory
File: Renaming/ScopeFactory.cs
Creates properly-formatted scopes:
public static class ScopeFactory
{
public static NamespaceScope Namespace(string name, NamespaceArea area = Internal);
public static TypeScope ClassSurface(TypeSymbol type, bool isStatic);
public static TypeScope ViewSurface(TypeSymbol type, StableId interfaceId, bool isStatic);
}
Name Reservation Table
File: Renaming/NameReservationTable.cs
Tracks reserved names per scope:
public sealed class NameReservationTable
{
public bool TryReserve(string name, StableId owner);
public bool IsReserved(string name);
public int AllocateNextSuffix(string baseName);
}
Conflict Resolution
When a name is taken, numeric suffixes are added:
add -> add (first)
add -> add2 (conflict)
add -> add3 (conflict)
For explicit interface implementations, interface name is used:
clear -> clear (own method)
clear -> clear_ICollection (explicit impl)
TypeScript Reserved Words
File: Renaming/TypeScriptReservedWords.cs
private static readonly HashSet<string> Reserved = new()
{
// Keywords
"break", "case", "catch", "class", "const", "continue",
"debugger", "default", "delete", "do", "else", "enum",
"export", "extends", "false", "finally", "for", "function",
"if", "import", "in", "instanceof", "new", "null", "return",
"super", "switch", "this", "throw", "true", "try", "typeof",
"var", "void", "while", "with",
// Strict mode
"implements", "interface", "let", "package", "private",
"protected", "public", "static", "yield",
// Future reserved
"await", "async"
};
public static (string Sanitized, bool WasSanitized) Sanitize(string name)
{
if (Reserved.Contains(name))
return (name + "_", true);
return (name, false);
}
Style Transforms
CLR Style (default)
No transformation - PascalCase preserved:
Renamer.AdoptMemberStyleTransform(name => name);
// GetEnumerator -> GetEnumerator
// WriteLine -> WriteLine
JavaScript Style (--naming js)
camelCase transformation:
Renamer.AdoptMemberStyleTransform(name => ToCamelCase(name));
// GetEnumerator -> getEnumerator
// WriteLine -> writeLine
// XMLReader -> xmlReader
Rename Decisions
Every rename is recorded:
public sealed record RenameDecision
{
public StableId Id { get; }
public string Requested { get; } // Original name
public string Final { get; } // Final TypeScript name
public string From { get; } // Base name (without suffixes)
public string Reason { get; } // Why this decision
public string DecisionSource { get; } // Which component made decision
public string Strategy { get; } // None, NumericSuffix, OverloadFamily
public string ScopeKey { get; }
public bool? IsStatic { get; }
}
Strategies:
None- No rename neededNumericSuffix- Added numeric suffix (add2, add3)ReservedWord- Added underscore (default_)OverloadFamily- Shares name with overload family