Generate TypeScript from Enum

Hello everybody,

today I want to share with the world code, which generates typescript from enum declaration. I suppose everything should be understandable from code itself:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace System
{
public static class AttributesSimplification
{
/*
 
[Description("Enumerations")]
public enum EnumSample
{
[Description("Choice One")]
ChoiceOne,
 
[Description("Choice Two")]
ChoiceTwo,
}
 
   gives following ts:
 
module Enumerations {
export module EnumSample {
export enum Enum {
ChoiceOne = 0,
ChoiceTwo = 2
}
 
export function describe (enumValue: Enum) {
switch (enumValue) {
case Enum.ChoiceOne:
return "Choice One";
case Enum.ChoiceTwo:
return "Choice Two";
default:
throw Error("Unknown Enum Value");
}
}
}
}
export = Enumerations;
*/
 
 
 
// Since Enum Type implements IConvertible interface we can pass into method enum
//http://stackoverflow.com/questions/79126/create-generic-method-constraining-t-to-an-enum
public static string GetTypeScriptRepresentation<T>() where T :struct , IConvertible
{
if (!typeof(T).IsEnum)
{
throw new ArgumentException("T must be an enumerated type");
}
 
StringBuilder sb = new StringBuilder();
var defaultInstance = new T();
var values = Enum.GetValues(typeof(T)).Cast<T>().ToList();
var descAttribute = (DescriptionAttributeAttribute.GetCustomAttribute(defaultInstance.GetType(), typeof(DescriptionAttribute));
string moduleName = string.Empty;
 
if (descAttribute == null || string.IsNullOrEmpty(descAttribute.Description))
{
moduleName = defaultInstance.GetType().Namespace;
}
else
{
moduleName = descAttribute.Description;
}
 
var enumName = defaultInstance.GetType().Name;

string openingBr = "{";
string closingBr = "}";

sb.Append($"module {moduleName} \r\n {openingBr} \r\n");
sb.Append($"\texport module {enumName} \r\n\t {openingBr} \r\n");
sb.Append($"\t\texport enum Enum \r\n\t\t{openingBr}");
var lastValue = values[values.Count - 1];
foreach (var value in values)
{
var intPresentation = Convert.ToInt32(value as System.Enum);
sb.Append($"\r\n\t\t\t\t{value.ToString()} = {intPresentation.ToString()}" );

if (value.ToString() != lastValue.ToString())
{
sb.Append(",");
}
else
{
sb.Append("\r\n");
}
}
sb.Append($"\t\t{closingBr}");

sb.Append("\r\n\texport function describe (enumValue: Enum) \r\n\t{");
sb.Append("\r\n\t\tswitch (enumValue) \r\n\t\t{\r\n");

foreach (var value in values)
{
sb.Append("\t\t\t\tcase Enum.");
sb.Append(value.ToString());
sb.Append(":");
sb.Append("\r\n\t\t\t\t\t return \"" + GetDescription(value as System.Enum) + "\"");
sb.Append(";\r\n");
}

sb.Append("\t\t\tdefault:\r\n");
sb.Append("\t\t\t\tthrow Error(\"Unknown Enum Value\");");

sb.Append("\r\n\t\t\t}\r\n\t\t   }\r\n\t}\r\n}\r\n");
return sb.ToString();
}

public static void WriteFile(string filePath, string content)
{
if (System.IO.File.Exists(filePath))
{
IO.File.Delete(filePath);
}
System.IO.File.WriteAllText(filePath, content);
}

public static string GetDescription(this Enum value)
{
DescriptionAttribute attribute = value.GetType()
.GetField(value.ToString())
.GetCustomAttributes(typeof(DescriptionAttribute), false)
.SingleOrDefault() as DescriptionAttribute;
return attribute == null ? value.ToString() : attribute.Description;
}

public static T GetEnumValueFromDescription<T>(string description)
{
var type = typeof(T);
if (!type.IsEnum)
throw new ArgumentException();
var fields = type.GetFields();
var field = fields
.SelectMany(f => f.GetCustomAttributes(
typeof(DescriptionAttribute), false), (
f, a) => new { Field = f, Att = a }).SingleOrDefault(a => ((DescriptionAttribute)a.Att)
.Description == description);
return field == null ? default(T) : (T)field.Field.GetRawConstantValue();
}
}
}


Some examples of it's job:
AttributesSimplification.GetTypeScriptRepresentation<System.UriHostNameType>()
As result gives the following:
declare module System {
interface Uri {
AbsolutePath: string;
AbsoluteUri: string;
Authority: string;
DnsSafeHost: string;
Fragment: string;
Host: string;
        HostNameType: System.UriHostNameType.Enum;
IdnHost: string;
IsAbsoluteUri: boolean;
IsDefaultPort: boolean;
IsFile: boolean;
IsLoopback: boolean;
IsUnc: boolean;
LocalPath: string;
OriginalString: string;
PathAndQuery: string;
Port: number;
Query: string;
Scheme: string;
Segments: string[];
UserEscaped: boolean;
UserInfo: string;
}
}
If you'll have the following declaration:

[Description("DomainModels.Location")]
public enum LocationLevel
{
     //Country - ProvincePart levels do not use as they are in nuts codes but can be added if necesary
     Country = 1,
     CountryPart = 2,
     Province = 3,
     ProvincePart = 4,
     Municipality = 5,
     City = 6,
 }

Then with following code
AttributesSimplification.GetTypeScriptRepresentation<QCore.Portal.Models.DomainModels.Location.LocationLevel>()

you'll see the following TypeScript generated:
module DomainModels.Location 
{ 
export module LocationLevel 
 { 
export enum Enum 
{
Country = 1,
CountryPart = 2,
Province = 3,
ProvincePart = 4,
Municipality = 5,
City = 6
}
export function describe (enumValue: Enum) 
{
switch (enumValue) 
{
case Enum.Country:
 return "Country";
case Enum.CountryPart:
 return "CountryPart";
case Enum.Province:
 return "Province";
case Enum.ProvincePart:
 return "ProvincePart";
case Enum.Municipality:
 return "Municipality";
case Enum.City:
 return "City";
default:
throw Error("Unknown Enum Value");
}
   }
}
}
Take note, how attribute Description was applied.

One more example:
[Description("Models.DomainModels")]
public enum AwardStatus
{
     [Description("Still in progress")]
     StillInProgress,
     [Description("Awarded")]
     Awarded,
     [Description("Withdrawn")]
     Withdrawn
}
AttributesSimplification.GetTypeScriptRepresentation<DomainModels.AwardStatus>()
gives following TS:

module Models.DomainModels 
{ 
export module AwardStatus 
 { 
export enum Enum 
{
StillInProgress = 0,
Awarded = 1,
Withdrawn = 2
}
export function describe (enumValue: Enum) 
{
switch (enumValue) 
{
case Enum.StillInProgress:
 return "Still in progress";
case Enum.Awarded:
 return "Awarded";
case Enum.Withdrawn:
 return "Withdrawn";
default:
throw Error("Unknown Enum Value");
}
   }
}
}
So, if you need some kind of enums generation, you can use my utility.

No Comments

Add a Comment