Skip to content

Commit 734e992

Browse files
committed
first version
1 parent b20e49b commit 734e992

19 files changed

Lines changed: 1015 additions & 2 deletions

.gitattributes

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
###############################################################################
2+
# Set default behavior to automatically normalize line endings.
3+
###############################################################################
4+
* text=auto
5+
6+
###############################################################################
7+
# Set default behavior for command prompt diff.
8+
#
9+
# This is need for earlier builds of msysgit that does not have it on by
10+
# default for csharp files.
11+
# Note: This is only used by command line
12+
###############################################################################
13+
#*.cs diff=csharp
14+
15+
###############################################################################
16+
# Set the merge driver for project and solution files
17+
#
18+
# Merging from the command prompt will add diff markers to the files if there
19+
# are conflicts (Merging from VS is not affected by the settings below, in VS
20+
# the diff markers are never inserted). Diff markers may cause the following
21+
# file extensions to fail to load in VS. An alternative would be to treat
22+
# these files as binary and thus will always conflict and require user
23+
# intervention with every merge. To do so, just uncomment the entries below
24+
###############################################################################
25+
#*.sln merge=binary
26+
#*.csproj merge=binary
27+
#*.vbproj merge=binary
28+
#*.vcxproj merge=binary
29+
#*.vcproj merge=binary
30+
#*.dbproj merge=binary
31+
#*.fsproj merge=binary
32+
#*.lsproj merge=binary
33+
#*.wixproj merge=binary
34+
#*.modelproj merge=binary
35+
#*.sqlproj merge=binary
36+
#*.wwaproj merge=binary
37+
38+
###############################################################################
39+
# behavior for image files
40+
#
41+
# image files are treated as binary by default.
42+
###############################################################################
43+
#*.jpg binary
44+
#*.png binary
45+
#*.gif binary
46+
47+
###############################################################################
48+
# diff behavior for common document formats
49+
#
50+
# Convert binary document formats to text before diffing them. This feature
51+
# is only available from the command line. Turn it on by uncommenting the
52+
# entries below.
53+
###############################################################################
54+
#*.doc diff=astextplain
55+
#*.DOC diff=astextplain
56+
#*.docx diff=astextplain
57+
#*.DOCX diff=astextplain
58+
#*.dot diff=astextplain
59+
#*.DOT diff=astextplain
60+
#*.pdf diff=astextplain
61+
#*.PDF diff=astextplain
62+
#*.rtf diff=astextplain
63+
#*.RTF diff=astextplain

Generator.cs

Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using System.Reflection;
6+
using System.Text;
7+
using Mono.Cecil;
8+
9+
public static class Generator
10+
{
11+
public static TypeScriptInterface CreateInterface(string assemblyFile, string rootType)
12+
{
13+
var moduleDefinition = ModuleDefinition.ReadModule(assemblyFile);
14+
if (moduleDefinition == null)
15+
throw new ArgumentException(string.Format("The assembly '{0}' could not be loaded.", assemblyFile), "assemblyFile");
16+
17+
var typeDefintion = moduleDefinition.GetType(rootType);
18+
if (typeDefintion == null)
19+
throw new ArgumentException(string.Format("The type '{0}' could not be found.", rootType), "rootType");
20+
21+
var scriptInterface = new TypeScriptInterface();
22+
scriptInterface.Name = typeDefintion.Name;
23+
24+
// get all properties
25+
var propertyDefinitions = typeDefintion
26+
.Traverse(t => t.BaseType == null ? null : t.BaseType.Resolve())
27+
.SelectMany(t => t.Properties);
28+
29+
foreach (var propertyDefinition in propertyDefinitions)
30+
{
31+
var scriptPropery = new TypeScriptProperty();
32+
scriptPropery.Name = propertyDefinition.Name;
33+
34+
var propertyType = propertyDefinition.PropertyType;
35+
scriptPropery.Type = propertyType.ToScriptType();
36+
scriptPropery.IsNullable = propertyDefinition.PropertyType.IsNullable();
37+
scriptPropery.IsArray = propertyDefinition.PropertyType.IsScriptArray();
38+
scriptInterface.Properties.Add(scriptPropery);
39+
}
40+
41+
return scriptInterface;
42+
}
43+
}
44+
45+
public class TypeScriptInterface
46+
{
47+
public TypeScriptInterface()
48+
{
49+
Properties = new List<TypeScriptProperty>();
50+
}
51+
52+
public string Name { get; set; }
53+
54+
public string Extends { get; set; }
55+
56+
public List<TypeScriptProperty> Properties { get; set; }
57+
}
58+
59+
public class TypeScriptProperty
60+
{
61+
public string Name { get; set; }
62+
public string Type { get; set; }
63+
public bool IsNullable { get; set; }
64+
public bool IsArray { get; set; }
65+
66+
public override string ToString()
67+
{
68+
return string.Format("Name: {0}, Type: {1}, Nullable: {2}, Array: {3}", Name, Type, IsNullable, IsArray);
69+
}
70+
}
71+
72+
public static class Extensions
73+
{
74+
public static TypeReference GetUnderlyingType(this TypeReference type)
75+
{
76+
if (!type.IsGenericInstance)
77+
return type;
78+
79+
var genericType = type as GenericInstanceType;
80+
if (genericType == null)
81+
return type;
82+
83+
var genericDefinition = genericType.Resolve();
84+
if (genericDefinition.GenericParameters.Count != 1 && genericDefinition.FullName != "System.Nullable`1")
85+
return type;
86+
87+
return genericType.GenericArguments.Single();
88+
}
89+
90+
public static bool HasInterface(this TypeReference typeReference, string fullName)
91+
{
92+
TypeDefinition definition = typeReference.Resolve();
93+
94+
return definition.Interfaces
95+
.Select(i => i.Resolve())
96+
.Any(d => d.FullName == fullName);
97+
}
98+
99+
public static bool IsNullable(this TypeReference type)
100+
{
101+
bool isNullable = type.IsValueType == false;
102+
if (!type.IsGenericInstance)
103+
return isNullable;
104+
105+
var genericType = type as GenericInstanceType;
106+
if (genericType == null)
107+
return isNullable;
108+
109+
var genericDefinition = genericType.Resolve();
110+
if (genericDefinition.GenericParameters.Count == 1 && genericDefinition.FullName == "System.Nullable`1")
111+
return true;
112+
113+
return isNullable;
114+
}
115+
116+
public static bool IsScriptArray(this TypeReference typeReference)
117+
{
118+
var baseType = typeReference.GetUnderlyingType();
119+
if (baseType.FullName == "System.String" || baseType.FullName == "System.Byte[]")
120+
return false;
121+
122+
if (baseType.IsArray)
123+
return true;
124+
125+
TypeReference elementType = null;
126+
var isEnumerable = IsEnumerable(baseType, out elementType);
127+
if (isEnumerable)
128+
return true;
129+
130+
return false;
131+
}
132+
133+
public static bool IsEnumerable(this TypeReference typeReference, out TypeReference elementType)
134+
{
135+
elementType = null;
136+
137+
var collectionType = typeReference
138+
.Traverse(t => t.Resolve().BaseType)
139+
.FirstOrDefault(t => t.HasInterface("System.Collections.Generic.IEnumerable`1"));
140+
141+
var genericCollectionType = collectionType as GenericInstanceType;
142+
if (genericCollectionType == null)
143+
return false;
144+
145+
//NOTE issue with custom implementation and matching up argument position
146+
elementType = genericCollectionType.GenericArguments.Single();
147+
return true;
148+
}
149+
150+
public static bool IsCollection(this TypeReference typeReference, out TypeReference elementType)
151+
{
152+
elementType = null;
153+
154+
var collectionType = typeReference
155+
.Traverse(t => t.Resolve().BaseType)
156+
.FirstOrDefault(t => t.HasInterface("System.Collections.Generic.ICollection`1"));
157+
158+
var genericCollectionType = collectionType as GenericInstanceType;
159+
if (genericCollectionType == null)
160+
return false;
161+
162+
//NOTE issue with custom implementation and matching up argument position
163+
elementType = genericCollectionType.GenericArguments.Single();
164+
return true;
165+
}
166+
167+
public static bool IsDictionary(this TypeReference typeReference, out TypeReference keyType, out TypeReference elementType)
168+
{
169+
keyType = null;
170+
elementType = null;
171+
172+
var dictionaryType = typeReference
173+
.Traverse(t => t.Resolve().BaseType)
174+
.FirstOrDefault(t => t.HasInterface("System.Collections.Generic.IDictionary`2"));
175+
176+
var genericDictionaryType = dictionaryType as GenericInstanceType;
177+
if (genericDictionaryType == null)
178+
return false;
179+
180+
//NOTE issue with custom implementation and matching up argument position
181+
keyType = genericDictionaryType.GenericArguments.First();
182+
elementType = genericDictionaryType.GenericArguments.Last();
183+
184+
return true;
185+
}
186+
187+
public static string ToScriptType(this TypeReference typeReference)
188+
{
189+
var t = typeReference.GetUnderlyingType();
190+
191+
switch (t.Name)
192+
{
193+
case "Int16":
194+
case "Int32":
195+
case "Int64":
196+
case "Byte":
197+
case "Decimal":
198+
case "Double":
199+
case "SByte":
200+
case "Single":
201+
case "UInt16":
202+
case "UInt32":
203+
case "UInt64":
204+
return "number";
205+
case "Boolean":
206+
return "boolean";
207+
case "DateTime":
208+
case "DateTimeOffset":
209+
return "Date";
210+
case "String":
211+
case "Guid":
212+
case "TimeSpan":
213+
return "string";
214+
case "Byte[]":
215+
return "string";
216+
default:
217+
return "any";
218+
}
219+
}
220+
221+
222+
public static IEnumerable<T> Traverse<T>(this T root, Func<T, IEnumerable<T>> childrenSelector)
223+
{
224+
yield return root;
225+
226+
IEnumerable<T> descendants = childrenSelector(root);
227+
if (descendants == null)
228+
yield break;
229+
230+
foreach (T descendant in descendants.SelectMany(element => element.Traverse(childrenSelector)))
231+
yield return descendant;
232+
}
233+
234+
public static IEnumerable<T> Traverse<T>(this T root, Func<T, T> childrenSelector) where T : class
235+
{
236+
T descendant = root;
237+
while (descendant != null)
238+
{
239+
yield return descendant;
240+
descendant = childrenSelector(descendant);
241+
}
242+
}
243+
244+
245+
public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
246+
{
247+
return source.DistinctBy(keySelector, EqualityComparer<TKey>.Default);
248+
}
249+
250+
public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
251+
{
252+
if (source == null)
253+
throw new ArgumentNullException("source");
254+
if (keySelector == null)
255+
throw new ArgumentNullException("keySelector");
256+
if (comparer == null)
257+
throw new ArgumentNullException("comparer");
258+
259+
var knownKeys = new HashSet<TKey>(comparer);
260+
return source.Where(element => knownKeys.Add(keySelector(element)));
261+
}
262+
}

README.md

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,37 @@
1-
TypeScriptGenerator
2-
===================
1+
#TypeScriptGenerator
32

43
CodeSmith Template to generate TypeScript interface for .NET a class
4+
5+
[![Build status](https://ci.appveyor.com/api/projects/status/5wonpaggu8m843wd/branch/master?svg=true)](https://ci.appveyor.com/project/LoreSoft/typescriptgenerator/branch/master)
6+
7+
##Download
8+
9+
The templates are available on nuget.org via package name `TypeScriptGenerator`.
10+
11+
To install TypeScriptGenerator, run the following command in the Package Manager Console
12+
13+
PM> Install-Package TypeScriptGenerator
14+
15+
More information about NuGet package avaliable at
16+
https://nuget.org/packages/TypeScriptGenerator
17+
18+
##Development Builds
19+
20+
Development builds are available on the myget.org feed. A development build is promoted to the main NuGet feed when it's determined to be stable.
21+
22+
In your Package Manager settings add the following package source for development builds:
23+
http://www.myget.org/F/loresoft/
24+
25+
26+
## License
27+
28+
Copyright (c) 2014, LoreSoft
29+
All rights reserved.
30+
31+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
32+
33+
- Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
34+
- Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
35+
- Neither the name of LoreSoft nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
36+
37+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
7+
namespace TypeScriptGenerator.Sample
8+
{
9+
public abstract class Pet
10+
{
11+
public string Name { get; set; }
12+
13+
public int Age { get; set; }
14+
15+
}
16+
17+
public class Dog : Pet
18+
{
19+
public string Bread { get; set; }
20+
}
21+
22+
public class Cat : Pet
23+
{
24+
public string Family { get; set; }
25+
}
26+
}

0 commit comments

Comments
 (0)