Пример #1
0
        private static string ExtractEnumerableType(Type type, TypeScriptContext context)
        {
            Type enumerableGenericArgument = null;

            if (type.IsInterface && type.IsConstructedGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable <>))
            {
                enumerableGenericArgument = type.GetGenericArguments().Single();
            }
            else if (type.IsInterface && type == typeof(IEnumerable))
            {
                enumerableGenericArgument = typeof(object);
            }
            else
            {
                enumerableGenericArgument = type.GetInterfaces()
                                            .FirstOrDefault(i => i.IsConstructedGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable <>))
                                            ?.GetGenericArguments().Single();
            }

            if (enumerableGenericArgument != null)
            {
                return($"Array<{GetTypeRef(enumerableGenericArgument, context)}>");
            }

            return(null);
        }
Пример #2
0
        private static IEnumerable <MemberDefinition> GetMembers(Type type, TypeScriptContext context)
        {
            var shouldGenerateMember = context.Options.ShouldGenerateMember;

            if (shouldGenerateMember == null)
            {
                return(Enumerable.Empty <MemberDefinition>());
            }
            var memberRenamer = context.Options.MemberRenamer ?? new Func <MemberInfo, string>(x => x.Name);
            var useDecorators = context.Options.UseDecorators ?? new Func <MemberInfo, IEnumerable <string> >(_ => (new List <string>()));


            var memberDefs = type.GetFields(BindingFlags)
                             .Select(f => {
                var fieldType = f.FieldType;
                var nullable  = false;
                if (fieldType.IsGenericType && fieldType.GetGenericTypeDefinition() == typeof(Nullable <>))
                {
                    // choose the generic parameter, rather than the nullable
                    fieldType = fieldType.GetGenericArguments()[0];
                    nullable  = true;
                }

                var memberDefinition = new MemberDefinition(memberRenamer(f), GetTypeRef(fieldType, context), nullable, useDecorators(f).ToList());
                if (shouldGenerateMember(f, memberDefinition))
                {
                    return(memberDefinition);
                }

                return(null);
            })
                             .ToList();

            memberDefs.AddRange(
                type.GetProperties(BindingFlags)
                .Select(p =>
            {
                var propertyType = p.PropertyType;
                var nullable     = false;
                if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(Nullable <>))
                {
                    // choose the generic parameter, rather than the nullable
                    propertyType = propertyType.GetGenericArguments()[0];
                    nullable     = true;
                }

                var memberDefinition = new MemberDefinition(memberRenamer(p), GetTypeRef(propertyType, context), nullable,
                                                            useDecorators(p).ToList());
                if (shouldGenerateMember(p, memberDefinition))
                {
                    return(memberDefinition);
                }

                return(null);
            }).ToList()
                );

            return(memberDefs.Where(md => md != null).ToList());
        }
Пример #3
0
        private static List <string> GetInterfaces(Type type, TypeScriptContext context)
        {
            var interfaces = type.GetInterfaces().ToList();

            return(interfaces
                   .Except(type.BaseType?.GetInterfaces() ?? Enumerable.Empty <Type>())
                   .Except(interfaces.SelectMany(i => i.GetInterfaces())) // get only implemented by this type
                   .Where(i => PopulateTypeDefinition(i, context) != null)
                   .Select(i => GetTypeRef(i, context))
                   .ToList());
        }
Пример #4
0
        internal static string GenerateTypeScript(IEnumerable <Type> types, TypeScriptOptions options)
        {
            var context = new TypeScriptContext(options);

            GetTypeScriptDefinitions(types, context);

            Handlebars.Configuration.TextEncoder = SimpleEncoder.Instance;

            var generator = Handlebars.Compile(Template);

            return(generator(context));
        }
Пример #5
0
        private static IEnumerable <MemberDefinition> GetMembers(Type type, TypeScriptContext context)
        {
            var memberDefs = type.GetFields(BindingFlags)
                             .Select(f => new MemberDefinition(f.Name, GetTypeRef(f.FieldType, context)))
                             .ToList();

            memberDefs.AddRange(
                type.GetProperties(BindingFlags)
                .Select(p => new MemberDefinition(p.Name, GetTypeRef(p.PropertyType, context)))
                );

            return(memberDefs);
        }
Пример #6
0
        private static string GetTypeRef(Type type, TypeScriptContext context)
        {
            if (type.IsGenericParameter)
            {
                return(type.Name);
            }

            if (type.IsEnum)
            {
                var enumDef = PopulateEnumDefinition(type, context);
                return(enumDef != null ? enumDef.Name : "any");
            }

            var typeCode = GetTypeCode(type);

            if (typeCode != TypeCode.Object)
            {
                return(GetPrimitiveMemberType(typeCode, context.Options));
            }

            var dictionaryType = ExtractDictionaryType(type, context);

            if (dictionaryType != null)
            {
                return(dictionaryType);
            }

            var enumerableType = ExtractEnumerableType(type, context);

            if (enumerableType != null)
            {
                return(enumerableType);
            }

            var typeDef = PopulateTypeDefinition(type, context);

            if (typeDef == null)
            {
                return("any");
            }

            var typeName = typeDef.Name;

            if (type.IsGenericType)
            {
                var genericPrms = type.GetGenericArguments().Select(t => GetTypeRef(t, context));
                return($"{typeName}<{string.Join(", ", genericPrms)}>");
            }

            return(typeName);
        }
Пример #7
0
 private static void GetTypeScriptDefinitions(IEnumerable <Type> types, TypeScriptContext context)
 {
     foreach (var type in types)
     {
         if (!type.IsEnum)
         {
             PopulateTypeDefinition(type, context);
         }
         else
         {
             PopulateEnumDefinition(type, context);
         }
     }
 }
Пример #8
0
        private static string ApplyRename(string typeName, TypeScriptContext context)
        {
            var options = context.Options;

            typeName = options.TypeRenamer != null?options.TypeRenamer(typeName) : typeName;

            var checkName = typeName;
            var i         = 1;

            while (context.Types.Any(td => td.Name == checkName))
            {
                checkName = $"{typeName}${i++}";
            }

            return(checkName);
        }
Пример #9
0
        private static string ExtractDictionaryType(Type type, TypeScriptContext context)
        {
            var dictionaryInterface = type.GetInterfaces().Concat(new[] { type }).FirstOrDefault(t =>
                                                                                                 t.IsConstructedGenericType && t.GetGenericTypeDefinition() == typeof(IDictionary <,>));

            if (dictionaryInterface == null)
            {
                return(null);
            }

            var genericArguments = dictionaryInterface.GetGenericArguments();
            var keyType          = GetTypeRef(genericArguments[0], context);
            var valueType        = GetTypeRef(genericArguments[1], context);

            return($"{{ [key: {keyType}]: {valueType} }}");
        }
Пример #10
0
        private static IEnumerable <MethodDefinition> GetMethods(Type type, TypeScriptContext context)
        {
            var shouldGenerateMethod = context.Options.ShouldGenerateMethod;

            if (shouldGenerateMethod == null)
            {
                return(Enumerable.Empty <MethodDefinition>());
            }

            var useDecorators = context.Options.UseDecorators ?? (_ => new List <string>());
            var memberRenamer = context.Options.MemberRenamer ?? (x => x.Name);

            var retVal  = new List <MethodDefinition>();
            var methods = type.GetMethods(BindingFlags).Where(m => !m.IsSpecialName);

            foreach (var method in methods)
            {
                string declaration;
                if (method.IsGenericMethod)
                {
                    var methodName = memberRenamer(method);

                    var genericPrms = method.GetGenericArguments().Select(t => GetTypeRef(t, context));
                    declaration = $"{methodName}<{string.Join(", ", genericPrms)}>";
                }
                else
                {
                    declaration = memberRenamer(method);
                }

                var parameters = method.GetParameters()
                                 .Select(p => new MemberDefinition(p.Name, GetTypeRef(p.ParameterType, context)));

                var decorators = useDecorators(method);

                var methodDefinition = new MethodDefinition(declaration, parameters, decorators);

                if (shouldGenerateMethod(method, methodDefinition))
                {
                    retVal.Add(methodDefinition);
                }
            }

            return(retVal);
        }
Пример #11
0
        private static string GetTypeRef(Type type, TypeScriptContext context)
        {
            if (type.IsGenericParameter)
            {
                return(type.Name);
            }

            if (type.IsEnum)
            {
                var enumDef = PopulateEnumDefinition(type, context);
                return(enumDef != null ? enumDef.Name : "any");
            }

            var typeCode = Type.GetTypeCode(type);

            if (typeCode != TypeCode.Object)
            {
                return(GetPrimitiveMemberType(typeCode, context.Options));
            }

            var enumerable = type.GetInterfaces()
                             .FirstOrDefault(i => i.IsConstructedGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable <>));

            if (enumerable != null)
            {
                return($"Array<{GetTypeRef(enumerable.GetGenericArguments().First(), context)}>");
            }

            var typeDef = PopulateTypeDefinition(type, context);

            if (typeDef == null)
            {
                return("any");
            }

            var typeName = typeDef.Name;

            if (type.IsGenericType)
            {
                var genericPrms = type.GetGenericArguments().Select(t => GetTypeRef(t, context));
                return($"{typeName}<{string.Join(", ", genericPrms)}>");
            }

            return(typeName);
        }
Пример #12
0
        private static EnumDefinition PopulateEnumDefinition(Type type, TypeScriptContext context)
        {
            var existing = context.Enums.FirstOrDefault(t => t.ClrType == type);

            if (existing != null)
            {
                return(existing);
            }

            var members = Enum.GetNames(type)
                          .Select(n => new EnumField(n, Convert.ToInt32(Enum.Parse(type, n)).ToString()));

            var def = new EnumDefinition(type, ApplyRename(type.Name, context), members);

            context.Enums.Add(def);

            return(def);
        }
Пример #13
0
        private static TypeDefinition PopulateTypeDefinition(Type type, TypeScriptContext context)
        {
            if (type.IsGenericParameter)
            {
                return(null);
            }
            var typeCode = Type.GetTypeCode(type);

            if (typeCode != TypeCode.Object)
            {
                return(null);
            }
            if (SkipCheck(type.ToString(), context.Options))
            {
                return(null);
            }

            if (type.IsConstructedGenericType)
            {
                type.GetGenericArguments().ToList().ForEach(t => PopulateTypeDefinition(t, context));
                type = type.GetGenericTypeDefinition();
            }

            var existing = context.Types.FirstOrDefault(t => t.ClrType == type);

            if (existing != null)
            {
                return(existing);
            }

            var interfaceRefs = GetInterfaces(type, context);

            var useInterface = context.Options.UseInterfaceForClasses;
            var isInterface  = type.IsInterface || (useInterface != null && useInterface(type));
            var baseTypeRef  = string.Empty;

            if (type.IsClass)
            {
                if (type.BaseType != typeof(object) && PopulateTypeDefinition(type.BaseType, context) != null)
                {
                    baseTypeRef = GetTypeRef(type.BaseType, context);
                }
                else if (context.Options.DefaultBaseType != null)
                {
                    baseTypeRef = context.Options.DefaultBaseType(type);
                }
            }

            string declaration, typeName;

            if (!type.IsGenericType)
            {
                typeName = declaration = ApplyRename(type.Name, context);
            }
            else
            {
                var genericPrms = type.GetGenericArguments().Select(g => {
                    var constraints = g.GetGenericParameterConstraints()
                                      .Where(c => PopulateTypeDefinition(c, context) != null)
                                      .Select(c => GetTypeRef(c, context))
                                      .ToList();

                    if (g.IsClass &&
                        (useInterface == null || !useInterface(type)) &&
                        g.GenericParameterAttributes.HasFlag(GenericParameterAttributes.DefaultConstructorConstraint))
                    {
                        constraints.Add($"{{ new(): {g.Name} }}");
                    }

                    if (constraints.Any())
                    {
                        return($"{g.Name} extends {string.Join(" & ", constraints)}");
                    }

                    return(g.Name);
                });

                typeName = ApplyRename(StripGenericFromName(type.Name), context);
                var genericPrmStr = string.Join(", ", genericPrms);
                declaration = $"{typeName}<{genericPrmStr}>";
            }

            CtorDefinition ctor = null;

            if (isInterface)
            {
                declaration = $"export interface {declaration}";

                if (!string.IsNullOrEmpty(baseTypeRef))
                {
                    interfaceRefs.Insert(0, baseTypeRef);
                }
            }
            else
            {
                var abs = type.IsAbstract ? " abstract" : string.Empty;
                declaration = $"export{abs} class {declaration}";

                if (!string.IsNullOrEmpty(baseTypeRef))
                {
                    declaration = $"{declaration} extends {baseTypeRef}";
                }

                var ctorGenerator = context.Options.CtorGenerator;
                if (ctorGenerator != null)
                {
                    ctor = ctorGenerator(type);
                }
            }

            if (interfaceRefs.Any())
            {
                var imp             = isInterface ? "extends" : "implements";
                var interfaceRefStr = string.Join(", ", interfaceRefs);
                declaration = $"{declaration} {imp} {interfaceRefStr}";
            }

            var typeDef = new TypeDefinition(type, typeName, declaration, ctor);

            context.Types.Add(typeDef);
            typeDef.Members.AddRange(GetMembers(type, context));
            typeDef.Methods.AddRange(GetMethods(type, context));

            return(typeDef);
        }
Пример #14
0
        private static string GetTypeRef(Type type, TypeScriptContext context)
        {
            if (type.IsGenericParameter)
            {
                return(type.Name);
            }

            if (type.IsEnum)
            {
                var enumDef = PopulateEnumDefinition(type, context);
                return(enumDef != null ? enumDef.Name : "any");
            }

            var typeCode = Type.GetTypeCode(type);

            if (typeCode != TypeCode.Object)
            {
                return(GetPrimitiveMemberType(typeCode, context.Options));
            }

            Type dictionaryType;

            if (IsClosedDictionaryType(type))
            {
                dictionaryType = type;
            }
            else
            {
                dictionaryType = type.GetInterfaces().FirstOrDefault(IsClosedDictionaryType);
            }

            if (dictionaryType != null)
            {
                var keyType   = type.GetGenericArguments().ElementAt(0);
                var valueType = type.GetGenericArguments().ElementAt(1);
                return($"Record<{GetTypeRef(keyType, context)}, {GetTypeRef(valueType, context)}>");
            }

            Type enumerable;

            if (IsClosedEnumerableType(type))
            {
                enumerable = type;
            }
            else
            {
                enumerable = type.GetInterfaces().FirstOrDefault(IsClosedEnumerableType);
            }

            if (enumerable != null)
            {
                return($"Array<{GetTypeRef(enumerable.GetGenericArguments().First(), context)}>");
            }

            var typeDef = PopulateTypeDefinition(type, context);

            if (typeDef == null)
            {
                return("any");
            }

            var typeName = typeDef.Name;

            if (type.IsGenericType)
            {
                var genericPrms = type.GetGenericArguments().Select(t => GetTypeRef(t, context));
                return($"{typeName}<{string.Join(", ", genericPrms)}>");
            }

            return(typeName);
        }