Start a new topic

using TypeScript definition files to generate C# bindings/wrappers for javascript libraries

It's great that now we can use our C# classes in typescript, as version 1.0 made it availablefor us.

I'm wondering that could we use the typescript definition files to generate C# bindings/wrappers?  It would made many javascript libraries and frameworks (aurelia, angular, ...) available/accessible in our C# code. 


What dou you think about this? 


This is very good idea and actually here we have an internal tool that does exactly what you mentioned. Currently this tool is very basic and have limitations which requires manual tuning after TS -> C# converted. With this tool we actually ported lib.d.ts automatically.

Thanks

Good to read! I hope you will be able to complete and publish this internal tool for us to make development almost totally transparent between C# and typescript.

Thanks for your hard work!  

Can i PLEASE get a copy of this tool.


I am trying to convert (BY HAND) webix.d.ts (Almost 8000 lines of code).


This tool would be a great help... no matter if i gotta go fixup the converted code after...


Beter than HAND writting 8000 lines code.


1 person likes this

I have made a converter for Typescript to Bridge code but assume Bridge and DuoCode are similar.

Here it is converted to Bridge.

7z
(132 KB)

Hey Michael...


First Off... Great work on the converter... i seem to having a problem with the GenericRead Function...

It just goes off into lala land... Eventually it get an out of memory error with 134,217,728 items added to the typeArguments List<string>


Typescript files that do not use generics works great... But soon as you try to convert ... say Jquery or anything that uses generics ... it bombs out.... I can really tell what you are try to do in GenericRead with the "ENDLESS WHILE LOOP"... But hopefully you can fix that little issue.

Michael...


I really need your help in fixing the Typescript converter... The GenericRead function hangs

when converting multi generic types... Never finds the last... while loop endless:


   interface SingleGeneric<T1> {
 test(one: T1, two: T1, three: TestArray<T1>[]): any;
 }

 interface MultiGeneric<T1, T2, U1, U2> {
 test(one: T1, two: T2, three: TestArray<U1, U2>[]): any;
 }



Try your converter with the SingleGeneric and MultiGeneric definitions.


The SingleGeneric WORK FINE...


But the MultiGeneric CRASHES the converter.. it can't handle <T1, T2>


That whole SkipToEndOfWord it not working if finds "<" but NOT ">"...


I can't really tell what you are trying to there with the WHERES Dictionary as well... 


Please Help me fix that... I really need that part to work.

Never mind... I just re-wrote some of the pieces to support DuoCode and a few other fixes like complex generics. I re-wrote the GenericRead and modified the SkipToEndOfWord, No endless while loop... Added a CloseGeneric method to find end of complex generics:


 

		static string SkipToEndOfWord(string tsFile, ref int index, bool formatGenerics = true)
		{
			if (!char.IsLetter(tsFile, index))
				SkipEmpty(tsFile, ref index);
			if (tsFile[index] == '[')
				return string.Empty;
			string result = "";
			for (; index < tsFile.Length; index++) {
				var item = tsFile[index];
				if (char.IsLetterOrDigit(item) || item == '[' || item == ']' || item == '<' || item == '>' || item == '_' || item == '.' || item == '$')
					result += item;
				else {
					if (result.EndsWith("]") && !result.EndsWith("[]")) {
						index--;
						result = result.Substring(0, result.Length - 1);
					}
					// Mackey Kinard
					if (formatGenerics) {
						GenericRead(tsFile, ref index, ref result);
					}
					return result;
				}
			}
			// Mackey Kinard
			if (formatGenerics) {
				GenericRead(tsFile, ref index, ref result);
			}
			return result;
		}
		//
		static Dictionary<string, string> GenericRead(string tsFile, ref int index, ref string word, bool arrays = true)
		{
			SkipEmpty(tsFile, ref index);
			Dictionary<string, string> whereTypesExt = new Dictionary<string, string>();
			if (word.Contains('<') && !word.Contains('>')) {
				index -= word.Length - word.IndexOf('<');
				word = word.Substring(0, word.IndexOf('<'));
				//Console.WriteLine(String.Format("Reading complex generic: {0}", word));
				int marker = CloseGeneric(tsFile, index);
				if (marker > index) {
					string insides = tsFile.Substring(index + 1, (marker - index) - 1);
					word += "<";
					string[] targs = insides.Split(',');
					foreach (string targ in targs) {
						if (targ.IndexOf("extends", StringComparison.Ordinal) >= 0 || targ.IndexOf("implements", StringComparison.Ordinal) >= 0) {
							string buffer = targ.Replace("extends", "|").Replace("implements", "|");
							string[] items = buffer.Split('|');
							string types = items[0].Trim();
							string wheres = items[1].Trim();
							whereTypesExt.Add(types, wheres);
							word += (types.Trim() + ", ");
						} else {
							word += (targ.Trim() + ", ");
						}
					}
					word = word.TrimEnd(',', ' ');
					word += ">";
					index = (marker + 1);
					SkipEmpty(tsFile, ref index);
					if (arrays) {
						char array1 = tsFile[index];
						char array2 = tsFile[index + 1];
						if (array1.Equals('[') && array2.Equals(']')) {
							word += "[]";
							index += 2;
							SkipEmpty(tsFile, ref index);
						}
					}
				} else {
					throw new Exception("Invalid Generic Type Syntax Detected For Word: " + word);
				}
			}
			return whereTypesExt;
		}
		//
		static int CloseGeneric(string tsFile, int index)
		{
			int marker = -1;
			for (; index < tsFile.Length; index++) {
				char check = tsFile[index];
				if (check.Equals('>')) {
					marker = index;
					break;
				}
			}
			return marker;
		}

 


Then... Every where there is a GenericRead, it has a SkipToEndOfWord BEFORE it... I default formatGenerics to true in the SkipToEndOfWord... EXCEPT when called RIGHT BEFORE a GenericRead... That way the SkipToEndOfWord ALWAYS formats the complex generic types EXCEPT when the GenericRead will do it... but the GenericRead ALSO returns the wheres dictionary... WORKS GREAT.. So far... 


FINALLY... I can auto generate c# bindings 95% (if not 100%... Only minor syntax changes need depending on how complex the typescript file is) of the way there.


THANKS MICHAEL SOOOO MUCH FOR MAKING THIS FOR BRIDGE... WAS NOT THAT HARD TO CONVERT TO DUOCODE....


THANK YOU, THANK YOU, THANK YOU!!! 


I am attaching a bootstrap.d.cs and a webix.d.cs (Formatted For DuoCode... Requires Any.cs)


STILL WORKING ON JQUERY

cs
(653 KB)
cs
(7.13 KB)
cs
(6.29 KB)

I want to also comment... that webix.d.ts was HUGE... All i had to change in the original typescript file was the nested namespace. Bootstrap was real small and went right thru with no changes needed to the output bootstrap.d.cs file (Once namespace was added to typescript file).


Note: the typescript MUST have at least one main namespace... So if it does not, like bootstrap... Just wrap the definitions in a declare namespace { code block }


the original typescript file had:

 

declare namespace webix {
 ...
 namespace ui {
 ...
 }
}

 

THE ONLY CHANGE I MADE TO TYPESCRIPT FILE WAS CHANGE THE INNER NAMESPACE

 TO namespace webix.ui

 

declare namespace webix {
 ...
 namespace webix.ui {
 ...
 }
}


That synced up all the other code that had hard coded reference to things like: webix.ui.baseView 


The converter made everything EXACTLY, NO CODE CHANGES... EVEN Any<> types on both properties and method parameters... SO NO BUNCH OVER OVERLOADS AND NO DYNAMIC for multiple options on properties that can have more that one value type.


But note... the webix does NOT have such complex properties and methods as JQuery does... So some you have to tweak output .cs files and others you dont.


So... Anyone interested ... Please download and try them out, let me know what you think.

Sorry... Correction on the bootstrap changes... I also added JQuery object IEnumerable support to the output .cs file... BUT... that DOES NOT have anything to do with the converter. That is just some sugar i put onto the output cs jQuery object to make easier to foreach thru the Jquery results.


Note: You can easily add extensions and helper functions to your output classes to make them EVEN more csharpie feel to using the API.


Just wanted to clarify where the IEnumerable support came from on the bootstrap JQuery object.

New Bootstrap.d.cs and webix.d.cs (Removed external dependency on Any.cs... 


Now uses Union<T1, T2...>)


Still working on minor changes to get JQuery to run with as little tweaks as possible that would need to be done to the output .cs file.

cs
(655 KB)
cs
(7.09 KB)

There is no need for [Js(Name="...")] in 99% of the time.


For example, the following

[Js(Name="backdrop")]

public extern Union<bool, string> backdrop { get; set; }


can be just simplified to:

public extern Union<bool, string> backdrop { get; set; }

The [Js(Name="name")] should only be used when there are capitals in the original, I'll look into it.

It should only do it when the first letter of the identifier is a capital. I'm sorry I haven't been around I have gone somewhere with no internet and am now at an internet café.

Login or Signup to post a comment