FileGenerator.Core 7.0.3

dotnet add package FileGenerator.Core --version 7.0.3
NuGet\Install-Package FileGenerator.Core -Version 7.0.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="FileGenerator.Core" Version="7.0.3" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add FileGenerator.Core --version 7.0.3
#r "nuget: FileGenerator.Core, 7.0.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.
// Install FileGenerator.Core as a Cake Addin
#addin nuget:?package=FileGenerator.Core&version=7.0.3

// Install FileGenerator.Core as a Cake Tool
#tool nuget:?package=FileGenerator.Core&version=7.0.3

FileGenerator.Core

Description

This will help you generate your C# classes to Typescript intefaces, enums and more... You can also create your own custom generator that will make use of the generated interfaces or enums. I build this project for my personal use of generating typescript equivalent of C# codes and now I decided to make it in public use.

Note:

  • Currently this generator is useful for typescript checking as it will only generate interfaces

Table of Contents

Installation

  1. Install using nuget. Click Here
  2. Add the generator on your startup file
public static async Task Main(string[] args)
{
 //...
    await FileGeneratorCore.Run("..", options => // In my case i used ".." to watch all inside on my solutions 
        options
        .SetGeneratedRootDirs("Client/Generated") // Where the output folder of generated files
        .SetImportPrefix("@generated") // Optional: see the generated "tsconfig.json" on how to resolve import issues
        .ReplaceGenerateTs<long,string>() // Optional: Use for replacing the type gnerated
        .AddGenerateTs<HttpStatusCode>() // Optional: Use to generate extra type
        
        );

 //....
}

Usage

  • Use GenerateTs attribute

Exmaple:

[GenerateTs]
public enum MyEnum
{
    None,
    A,
    B,
    C = 50,
}

[GenerateTs]
public class MyClass
{
    public string? Id { get; set; }
    public string? Name { get; set; }
    public string? TheNullableType { get; set; }
    public dynamic? TheNullableTypeDynamic { get; set; }
}

[GenerateTs]
public class MyClassGeneric<TData, TDataExtra> : MyClass where TData : MyClass
{
    public TData SubClass { get; set; }
    public TDataExtra Extra { get; set; }
    public ICollection<MyClass>? ExtendedCollection { get; set; }
    public Dictionary<string, MyClass> MyDictionary { get; set; }
    public (string Test, int TestInt, MyClass MyClass) Tuple { get; set; }
}

It will generate:

enum MyEnum {
  None = 0,
  A = 1,
  B = 2,
  C = 50,
}
export default MyEnum;

export default interface MyClass {
  id?: string;
  name?: string;
  theNullableType?: string;
  theNullableTypeDynamic?: unknown;
}

export default interface MyClassGeneric<TData extends MyClass, TDataExtra> extends MyClass {
  extendedCollection?: MyClass[];
  extra?: TDataExtra;
  myDictionary: Record<string,MyClass>;
  subClass: TData;
  tuple: [string, number, MyClass];
}

How to create a custom generator

  • Create a class that will inherit to BaseFileGenerator
  • Implement Filter property.
  • Override Generate function.
  • Note: ⚠️ This custom generator is using Reflection type of generating
  • Other functions that can be overridden in BaseFileGenerator - GenerateAsync, Generates & GeneratesAsync
  • ❗Don't forget to call GenerateFile in order to generate file

Example: HubGenerator.cs

using FileGenerator.Core;
using Microsoft.AspNetCore.SignalR;
using System.Reflection;
using System.Text;
using static FileGenerator.Core.Helpers.GeneratorHelper;

namespace CMVirtualize.Web.Generators
{
    public sealed class HubGenerator : BaseFileGenerator
    {
        public override Func<Type, bool> Filter => type =>
            type.BaseType != null &&
            type.BaseType.IsGenericType &&
        !type.IsGenericType &&
            type.BaseType.GetGenericTypeDefinition().IsAssignableFrom(typeof(Hub<>));

        public override void Generate(Type type)
        {
            var typeOfReciever = type.BaseType!.GetGenericArguments()[0];

            var receiverMethods = typeOfReciever.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public)
                       .Where(method => method.IsPublic);
            var senderMethods = type.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public)
                       .Where(method => method.IsPublic && !method.GetParameters().Any(parameter => parameter.ParameterType == typeof(CancellationToken)));

            var streamMethods = type.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public)
                       .Where(method => method.IsPublic && method.GetParameters().Any(parameter => parameter.ParameterType == typeof(CancellationToken)));

            var imports = new List<string>();
            var content = new StringBuilder();
            var name = GetName(type, imports, false);
            content.AppendLine($$"""
                import { HubConnection, HubConnectionBuilder, LogLevel } from '@microsoft/signalr';
                export default class {{name}} {
                  public connection: HubConnection;
                  constructor(private url?: string) {
                    this.connection = new HubConnectionBuilder()
                        .withUrl(this.url || '/hub/{{name}}')
                        .configureLogging(process.env.ENV === 'development' ? LogLevel.Information: LogLevel.Error)
                        .withAutomaticReconnect()
                        .build();
                  }
                """);
            foreach (var method in senderMethods)
            {
                var parameters = method.GetParameters().Select(s => $"{s.Name}: {GetName(s.ParameterType, imports)}").ToList();
                var parameterNames = method.GetParameters().Select(s => s.Name).ToList();
                var camelCaseName = method.Name.ToLowerFirst();
                content.AppendLine($"  public {camelCaseName} = ({string.Join(", ", parameters)}) =>");
                content.AppendLine($"    this.connection.invoke('{method.Name}', {string.Join(", ", parameterNames)});");
            }
            foreach (var method in receiverMethods)
            {
                var parameters = method.GetParameters().Select(s => $"{s.Name}: {GetName(s.ParameterType, imports)}").ToList();
                var camelCaseName = method.Name.ToLowerFirst();
                content.AppendLine($"  public {camelCaseName} = (callback: ({string.Join(", ", parameters)}) => void) =>");
                content.AppendLine($"    this.connection.on('{method.Name}', callback);");
            }
            foreach (var method in streamMethods)
            {
                var parameters = method.GetParameters()
                    .Where(parameter => parameter.ParameterType != typeof(CancellationToken))
                    .Select(s => $"{s.Name}: {GetName(s.ParameterType, imports)}").ToList();
                var parameterNames = method.GetParameters()
                    .Where(parameter => (parameter.ParameterType != typeof(CancellationToken)))
                    .Select(s => s.Name).ToList();
                var camelCaseName = method.Name.ToLowerFirst();
                var returnType = GetName(method.ReturnType.GetGenericArguments()[0], imports);

                content.AppendLine($"  public {camelCaseName} = ({string.Join(", ", parameters)}) =>");
                content.AppendLine($"    this.connection.stream<{returnType}>('{method.Name}', {string.Join(", ", parameterNames)});");
            }
            content.AppendLine($"  public removeEvent = (name: '{string.Join("' | '", receiverMethods.Select(s => s.Name))}', method?: (...args: any[]) => void) =>");
            content.AppendLine("    method ? this.connection.off(name, method) : this.connection.off(name);");
            content.Append('}');

            GenerateFile($"{FileLocation(type)}.ts", CombineImportContent(content, imports));
        }
    }
}
GeneratorHelper
  • GetName - This will be use to get the name of the generated type as well as the import file location but you need to pass a var imports = new List<string>(); types in order to collate the import files needed from generator.
  • FileLocation - Use to get the location of the file.
  • CombineImportContent - Use to bombine the imports file and the content
Note:❗Don't forget to call GenerateFile in order to generate the file you want to generate

Build pipeline generation or CI

Execute the following command to generate on CI dotnet build "FileGenerator.Core"

License

TBD

How to Contribute

TBD

Not yet added in the Typescript Generator ⚠️

  • Generate a class instead of interface.
  • Read only properties
  • Static and constant value properties
  • Include functions in generated types
Product Compatible and additional computed target framework versions.
.NET net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in 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.