Giter Club home page Giter Club logo

typedocconverter's Introduction

Typedoc Converter

This is a typedoc json to C# bindings converter. Can be used as a TypeScript to C# bindings converter.

Build status: .NET

Compatibility Status

  • typedoc: 0.20
  • TypeScript: 3.9, 4.0, 4.1, 4.2

Languages support

  • Enums
    • Direct value
    • Referenced value
  • Interfaces
    • Inherits
    • Generics
    • Generics Constaints
    • Properties
    • Methods
    • Events
  • Classes
    • Constructors
    • Inherits
    • Generics
    • Generics Constaints
    • Properties
    • Methods
    • Events
    • Indexer
  • Types
    • String literals
    • Type literals
    • Type alias*
    • Union types
    • Intersection types
  • Split entities to different files
  • Auto rename conflict parameter names
  • WinRT/CLR async types support (IAsyncAction/IAsyncOperation<T> or Task/Task<T>)
  • Newtonsoft.Json and System.Text.Json for JSON serialization
  • Nullable Reference Types
  • Type validation

*: Partial support

Installation

dotnet tool install -g TypedocConverter

Quick start

TypeScript code input.ts:

declare namespace test {
  /**
   * The declaration of an enum
   */
  export enum MyEnum {
    A = 0,
    B = 1,
    C = 2,
    D = C
  }

  /**
   * The declaration of an interface
   */
  export interface MyInterface1 {
    /**
     * A method
     */
    testMethod(arg: string, callback: () => void): string;
    /**
     * An event
     * @event
     */
    onTest(listener: (e: MyInterface1) => void): void;
    /**
     * An property
     */
    readonly testProp: string;
  }

  /**
   * Another declaration of an interface
   */
  export interface MyInterface2<T> {
    /**
     * A method
     */
    testMethod(arg: T, callback: () => void): T;
    /**
     * An event
     * @event
     */
    onTest(listener: (e: MyInterface2<T>) => void): void;
    /**
     * An property
     */
    readonly testProp: T;
  }

  /**
   * The declaration of a class
   */
  export class MyClass1<T> implements MyInterface1 {
    /**
     * A method
     */
    testMethod(arg: string, callback: () => void): string;
    /**
     * An event
     * @event
     */
    onTest(listener: (e: MyInterface1) => void): void;
    /**
     * An property
     */
    readonly testProp: string;
    static staticMethod(value: string, isOption?: boolean): UnionStr;
  }

  /**
   * Another declaration of a class
   */
  export class MyClass2<T> implements MyInterface2<T> {
    /**
     * A method
     */
    testMethod(arg: T, callback: () => void): T;
    /**
     * An event
     * @event
     */
    onTest(listener: (e: MyInterface2<T>) => void): void;
    /**
     * An property
     */
    readonly testProp: T;
    static staticMethod(value: string, isOption?: boolean): UnionStr;
  }

  /**
   * The declaration of a type alias
   */
  export type UnionStr = "A" | "B" | "C" | "other";
}

With below commands (need a tsconfig.json):

typedoc input.ts --json output.json
TypedocConverter --inputfile output.json --outputfile output.cs

Voila! C# type bindings generated in output.cs:

namespace Test
{

    /// <summary>
    /// The declaration of an enum
    /// </summary>
    enum MyEnum
    {
        A = 0,
        B = 1,
        C = 2,
        D = 2
    }
}

namespace Test
{

    /// <summary>
    /// The declaration of a class
    /// </summary>
    class MyClass1<T> : MyInterface1
    {
        /// <summary>
        /// An event
        /// </summary>
        public event System.Action<MyInterface1> OnTest;

        /// <summary>
        /// An property
        /// </summary>
        [Newtonsoft.Json.JsonProperty("testProp", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
        public string TestProp { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); }

        /// <summary>
        /// A method
        /// </summary>
        public string TestMethod(string arg, System.Action callback) => throw new System.NotImplementedException();

        static UnionStr StaticMethod(string value, bool isOption) => throw new System.NotImplementedException();

    }
}

namespace Test
{

    /// <summary>
    /// Another declaration of a class
    /// </summary>
    class MyClass2<T> : MyInterface2<T>
    {
        /// <summary>
        /// An event
        /// </summary>
        public event System.Action<MyInterface2<T>> OnTest;

        /// <summary>
        /// An property
        /// </summary>
        [Newtonsoft.Json.JsonProperty("testProp", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
        public T TestProp { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); }

        /// <summary>
        /// A method
        /// </summary>
        public T TestMethod(T arg, System.Action callback) => throw new System.NotImplementedException();

        static UnionStr StaticMethod(string value, bool isOption) => throw new System.NotImplementedException();

    }
}

namespace Test
{

    /// <summary>
    /// The declaration of an interface
    /// </summary>
    interface MyInterface1
    {
        /// <summary>
        /// An event
        /// </summary>
        event System.Action<MyInterface1> OnTest;

        /// <summary>
        /// An property
        /// </summary>
        [Newtonsoft.Json.JsonProperty("testProp", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
        string TestProp { get; set; }

        /// <summary>
        /// A method
        /// </summary>
        string TestMethod(string arg, System.Action callback);

    }
}

namespace Test
{

    /// <summary>
    /// Another declaration of an interface
    /// </summary>
    interface MyInterface2<T>
    {
        /// <summary>
        /// An event
        /// </summary>
        event System.Action<MyInterface2<T>> OnTest;

        /// <summary>
        /// An property
        /// </summary>
        [Newtonsoft.Json.JsonProperty("testProp", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
        T TestProp { get; set; }

        /// <summary>
        /// A method
        /// </summary>
        T TestMethod(T arg, System.Action callback);

    }
}

namespace Test
{

    /// <summary>
    /// The declaration of a type alias
    /// </summary>
    [Newtonsoft.Json.JsonConverter(typeof(UnionStrConverter))]
    enum UnionStr
    {
        ///<summary>
        /// A
        ///</summary>
        A,
        ///<summary>
        /// B
        ///</summary>
        B,
        ///<summary>
        /// C
        ///</summary>
        C,
        ///<summary>
        /// other
        ///</summary>
        Other
    }

    class UnionStrConverter : Newtonsoft.Json.JsonConverter
    {
        public override bool CanConvert(System.Type t) => t == typeof(UnionStr) || t == typeof(UnionStr?);

        public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type t, object? existingValue, Newtonsoft.Json.JsonSerializer serializer)
            => reader.TokenType switch
            {
                Newtonsoft.Json.JsonToken.String =>
                    serializer.Deserialize<string>(reader) switch
                    {
                        "A" => UnionStr.A,
                        "B" => UnionStr.B,
                        "C" => UnionStr.C,
                        "other" => UnionStr.Other,
                        _ => throw new System.NotSupportedException("Cannot unmarshal type UnionStr")
                    },
                _ => throw new System.NotSupportedException("Cannot unmarshal type UnionStr")
            };

        public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object? untypedValue, Newtonsoft.Json.JsonSerializer serializer)
        {
            if (untypedValue is null) { serializer.Serialize(writer, null); return; }
            var value = (UnionStr)untypedValue;
            switch (value)
            {
                case UnionStr.A: serializer.Serialize(writer, "A"); return;
                case UnionStr.B: serializer.Serialize(writer, "B"); return;
                case UnionStr.C: serializer.Serialize(writer, "C"); return;
                case UnionStr.Other: serializer.Serialize(writer, "other"); return;
                default: break;
            }
            throw new System.NotSupportedException("Cannot marshal type UnionStr");
        }
    }
}

Build

cd TypedocConverter/TypedocConverter
dotnet publish -c Release -r win-x64 --no-self-contained /p:PublishSingleFile=true /p:PublishReadyToRun=true

You can replace win-x64 with other platform identifiers such as win-arm64, linux-x64, linux-arm64, osx-x64 and etc.
Then built dists will be placed in bin/Release/net7.0/[platform identifier]/publish

Native Build

cd TypedocConverter/TypedocConverter
dotnet publish -c Release -r win-x64 /p:PublishAot=true

You can replace win-x64 with other platform identifiers such as win-arm64, linux-x64, linux-arm64, osx-x64 and etc.
Then built dists will be placed in bin/Release/net7.0/[platform identifier]/publish

Run & Usage

TypedocConverter --help

Sample:

TypedocConverter --inputfile 1.json --splitfiles true --outputdir .

Arguments:

--inputfile [file]: input file
--namespace [namespace]: specify namespace for generated code
--splitfiles [true|false]: whether to split code to different files
--outputdir [path]: used for place code files when splitfiles is true
--outputfile [path]: used for place code file when splitfiles is false
--number-type [int/decimal/double...]: config for number type mapping
--promise-type [CLR/WinRT]: config for promise type mapping, CLR for Task and WinRT for IAsyncAction/IAsyncOperation
--any-type [object/dynamic...]: config for any type mapping
--array-type [Array/IEnumerable/List...]: config for array type mapping
--nrt-disabled [true|false]: whether to disable Nullable Reference Types
--json-mode [system|newtonsoft|both]: whether to use System.Text.Json or Newtonsoft.Json or both

Prebuilt binaries

We have prepared some prebuilt binaries for Windows, Linux and macOS.
You can download them directly from Releases

Prerequisites: .NET Runtime 7.0

typedocconverter's People

Contributors

hez2010 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

typedocconverter's Issues

Unable to convert a `Dictionary<string, T>`: System.Text.Json.JsonException: The JSON value could not be converted to Definitions+Reflection.

Description

An error occurs when trying to convert a pseudo-dictionary from TypeScript to C#.

Sample

Input

export interface SomeKindOfDictionary {
	[prop: string]: any;
}

typedoc

{
	"id": 0,
	"name": "@jsonforms/core",
	"kind": 0,
	"flags": {},
	"originalName": "",
	"children": [
		{
			"id": 1,
			"name": "\"packages/core/test\"",
			"kind": 1,
			"kindString": "Module",
			"flags": {
				"isExported": true
			},
			"originalName": "C:/Dev/Sandbox/jsonforms/packages/core/test.ts",
			"children": [
				{
					"id": 2,
					"name": "SomeKindOfDictionary",
					"kind": 256,
					"kindString": "Interface",
					"flags": {
						"isExported": true
					},
					"indexSignature": [
						{
							"id": 3,
							"name": "__index",
							"kind": 8192,
							"kindString": "Index signature",
							"flags": {
								"isExported": true
							},
							"parameters": [
								{
									"id": 4,
									"name": "prop",
									"kind": 32768,
									"kindString": "Parameter",
									"flags": {
										"isExported": true
									},
									"type": {
										"type": "intrinsic",
										"name": "string"
									}
								}
							],
							"type": {
								"type": "intrinsic",
								"name": "any"
							}
						}
					],
					"sources": [
						{
							"fileName": "packages/core/test.ts",
							"line": 1,
							"character": 37
						}
					]
				}
			],
			"groups": [
				{
					"title": "Interfaces",
					"kind": 256,
					"children": [
						2
					]
				}
			],
			"sources": [
				{
					"fileName": "packages/core/test.ts",
					"line": 1,
					"character": 0
				}
			]
		}
	],
	"groups": [
		{
			"title": "Modules",
			"kind": 1,
			"children": [
				1
			]
		}
	]
}

Error

Unhandled exception. System.Text.Json.JsonException: The JSON value could not be converted to Definitions+Reflection. Path: $.children[0].children[0].indexSignature | LineNumber: 25 | BytePositionInLine: 24.
   at System.Text.Json.ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(Type propertyType)
   at System.Text.Json.Serialization.Converters.ObjectWithParameterizedConstructorConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
   at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
   at System.Text.Json.Serialization.Converters.FSharpOptionConverter`2.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, TOption& value)
   at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
   at System.Text.Json.Serialization.JsonConverter`1.TryReadAsObject(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state, Object& value)
   at System.Text.Json.Serialization.Converters.LargeObjectWithParameterizedConstructorConverter`1.ReadAndCacheConstructorArgument(ReadStack& state, Utf8JsonReader& reader, JsonParameterInfo jsonParameterInfo)
   at System.Text.Json.Serialization.Converters.ObjectWithParameterizedConstructorConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
   at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
   at System.Text.Json.Serialization.JsonCollectionConverter`2.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, TCollection& value)
   at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
   at System.Text.Json.Serialization.Converters.FSharpOptionConverter`2.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, TOption& value)
   at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
   at System.Text.Json.Serialization.JsonConverter`1.TryReadAsObject(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state, Object& value)
   at System.Text.Json.Serialization.Converters.LargeObjectWithParameterizedConstructorConverter`1.ReadAndCacheConstructorArgument(ReadStack& state, Utf8JsonReader& reader, JsonParameterInfo jsonParameterInfo)
   at System.Text.Json.Serialization.Converters.ObjectWithParameterizedConstructorConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
   at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
   at System.Text.Json.Serialization.JsonCollectionConverter`2.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, TCollection& value)
   at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
   at System.Text.Json.Serialization.Converters.FSharpOptionConverter`2.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, TOption& value)
   at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
   at System.Text.Json.Serialization.JsonConverter`1.TryReadAsObject(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state, Object& value)
   at System.Text.Json.Serialization.Converters.LargeObjectWithParameterizedConstructorConverter`1.ReadAndCacheConstructorArgument(ReadStack& state, Utf8JsonReader& reader, JsonParameterInfo jsonParameterInfo)
   at System.Text.Json.Serialization.Converters.ObjectWithParameterizedConstructorConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
   at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
   at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
   at System.Text.Json.JsonSerializer.ReadFromSpan[TValue](ReadOnlySpan`1 utf8Json, JsonTypeInfo jsonTypeInfo, Nullable`1 actualByteCount)
   at System.Text.Json.JsonSerializer.ReadFromSpan[TValue](ReadOnlySpan`1 json, JsonTypeInfo jsonTypeInfo)
   at System.Text.Json.JsonSerializer.Deserialize[TValue](String json, JsonSerializerOptions options)
   at Program.main$cont@83(JsonSerializerOptions jsonOptions, Config config, Unit unitVar)
   at Program.main(String[] argv)

Typedoc function overloads don't generate correctly

For instance: https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.itextmodel.html#findmatches

Generates a single function with parameters for both overloads instead of two separate function signature declarations.

        /// <summary>
        /// Search the model.
        /// </summary>
        /// <returns>
        /// The ranges where the matches are. It is empty if not matches have been found.
        /// 
        /// </returns>
        /// <summary>
        /// Search the model.
        /// </summary>
        /// <returns>
        /// The ranges where the matches are. It is empty if no matches have been found.
        /// 
        /// </returns>
        IAsyncOperation<FindMatch[]> FindMatches(string searchString, bool searchOnlyEditableRange, bool isRegex, bool matchCase, string wordSeparators, bool captureMatches, double limitResultCount, string searchString1, IRange searchScope, bool isRegex1, bool matchCase1, string wordSeparators1, bool captureMatches1, double limitResultCount1);        

instead of

        /// <summary>
        /// Search the model.
        /// </summary>
        /// <returns>
        /// The ranges where the matches are. It is empty if not matches have been found.
        /// 
        /// </returns>
        IAsyncOperation<FindMatch[]> FindMatches(string searchString, bool searchOnlyEditableRange, bool isRegex, bool matchCase, string wordSeparators, bool captureMatches, double limitResultCount);

        /// <summary>
        /// Search the model.
        /// </summary>
        /// <returns>
        /// The ranges where the matches are. It is empty if no matches have been found.
        /// 
        /// </returns>
        IAsyncOperation<FindMatch[]> FindMatches(string searchString, IRange searchScope, bool isRegex, bool matchCase, string wordSeparators, bool captureMatches, double limitResultCount);

Refactor tests

We use json schema generated from monaco.d.ts for tests for now which is hard to verify test result.
Consider using multiple test cases instead.

4.0 Roadmap

4.0 Roadmap

We are planning what's next for TypedocConverter 4.0. Below work items are not guaranteed and subject to change.

  1. Drop typedoc dependency and use tsc API for source parsing
  2. Since we no longer use typedoc, we may change the project name
  3. Type validation (#11)
  4. Provide an option for generating API diff between old and new generated type bindings.

Dotnet Tool

First of all, thanks for this tool. I would like to use this in a ci scenario and for this it would be great to have this as a global dotnet tool (https://learn.microsoft.com/en-us/dotnet/core/tools/global-tools).

So I would like to request/suggest a deployment of this as a global dotnet tool next to the releases on github, so it can be installed during ci builds.

Sanitize properties with illegal characters

Some characters are allowed in TypeScript but not C#. TypedocConverter should sanitize them.

Example:

export interface JsonSchema4 {
  $ref?: string;
  //...
}

Currently outputs:

    interface JsonSchema4
    {
        [System.Text.Json.Serialization.JsonPropertyName("$ref")]
        string? $ref { get; set; }
        //...
    }

Instead of:

    interface JsonSchema4
    {
        [System.Text.Json.Serialization.JsonPropertyName("$ref")]
        string? Ref { get; set; }
        //...
    }

Generate "real" nested classes

Currently behavior of generating nested classes is generating the inner class under a namespace which has same name with its parent class name.

For example:

class Foo
{
    class Bar { }
}

will generate

class Foo { }
namespace Foo
{
    class Bar { }
}

This behavior should be changed to generate real nested classes.

Decorate with both System.Text.Json & Newtonsoft.Json attributes?

Hello,

As you may know, TypedocConverter will probably be used a lot for Blazor libraries in order to wrap existing JS/TS projects.

The users of the said Blazor library may vary, some will use it in a context that uses System.Text.Json and some Newtonsoft.Json.

The idea would be to change the arg --use-system-json so it could be something like [true|false|both] for instance.

Wdyt ?

System.Text.Json is always used?

After running into #18, I noticed in the README the possibility to use the --use-system-json argument. But even when using --use-system-json false, the error outputted is related to System.Text.Json. I would have expected an error related to Newtonsoft.Json.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.