/// <summary> /// Get custom property name if decorated by DataMemberAttribute or JsonPropertyAttribute. If not defined, return null. /// </summary> /// <param name="memberInfo"></param> /// <param name="methods"></param> /// <returns></returns> public static string GetFieldCustomName(MemberInfo memberInfo, CherryPickingMethods methods) { //opt-in for DataContract through DataMemberAttribute , and the type may or may not be decorated by DataContractAttribute. // Enum will have all member fields being picked, regardless of the EnumMemberAttribute. if ((methods & CherryPickingMethods.DataContract) == CherryPickingMethods.DataContract) { var a = TypeHelper.ReadAttribute <DataMemberAttribute>(memberInfo); if (a != null) { return(a.Name); } } //opt-in for NewtonsoftJson through JsonPropertyAttribute, , and the type may or may not be decorated by JsonObjectAttribute. if ((methods & CherryPickingMethods.NewtonsoftJson) == CherryPickingMethods.NewtonsoftJson) { // var a =TypeHelper.AttributeExists(memberInfo, "Newtonsoft.Json.JsonIgnoreAttribute"); var a = TypeHelper.ReadAttribute <Newtonsoft.Json.JsonIgnoreAttribute>(memberInfo); if (a == null) { var njAttribute = TypeHelper.ReadAttribute <Newtonsoft.Json.JsonPropertyAttribute>(memberInfo); if (njAttribute != null && !String.IsNullOrEmpty(njAttribute.PropertyName)) { return(njAttribute.PropertyName); } } } return(null); }
public void CreateCodeDom(Assembly assembly, CherryPickingMethods methods, DocCommentLookup docLookup) { this.docLookup = docLookup; var cherryTypes = PodGenHelper.GetCherryTypes(assembly, methods); CreateCodeDom(cherryTypes, methods); }
public static bool IsCherryType(Type type, CherryPickingMethods methods) { bool r0, r1, r2, r3, r4; r0 = r1 = r2 = r3 = r4 = false; if ((methods & CherryPickingMethods.DataContract) == CherryPickingMethods.DataContract) { r1 = TypeHelper.ReadAttribute <DataContractAttribute>(type) != null; } if ((methods & CherryPickingMethods.NewtonsoftJson) == CherryPickingMethods.NewtonsoftJson) { r2 = TypeHelper.AttributeExists(type, "Newtonsoft.Json.JsonObjectAttribute") != null; } if ((methods & CherryPickingMethods.Serializable) == CherryPickingMethods.Serializable) { r3 = TypeHelper.ReadAttribute <SerializableAttribute>(type) != null; } if ((methods & CherryPickingMethods.AspNet) == CherryPickingMethods.AspNet)//Asp.net does not seem to define good data annotation for cherry picking types { r4 = true; } if (methods == CherryPickingMethods.All) { r0 = true; } return(r0 | r1 | r2 | r3 | r4); }
static void Main(string[] args) { if (args.Length < 2) { Console.WriteLine("Poco2Ts.exe generates TypeScript data model interfaces from POCO classes."); Console.WriteLine(@"Example: For classes decorated by DataContractAttribute: Fonlow.Poco2Ts.exe MyAssemblyWithPOCO.dll MyOutputTS.ts For classes decorated by Newtonsoft.Json.JsonObjectAttribute: Fonlow.Poco2Ts.exe MyAssemblyWithPOCO.dll MyOutputTS.ts /2 For classes decorated by SerializableAttribute: Fonlow.Poco2Ts.exe MyAssemblyWithPOCO.dll MyOutputTS.ts /4 For public classes, properties and properties, and use System.ComponentModel.DataAnnotations.RequiredAttribute: Fonlow.Poco2Ts.exe MyAssemblyWithPOCO.dll MyOutputTS.ts /8 For all classes, properties and fields Fonlow.Poco2Ts.exe MyAssemblyWithPOCO.dll MyOutputTS.ts /0 "); return; } var assemblyName = args[0]; var tsFileName = args[1]; CherryPickingMethods methods = CherryPickingMethods.DataContract; if (args.Length > 2) { methods = ReadMethods(args[2]); } AppDomain appDomain = AppDomain.CurrentDomain; appDomain.AssemblyResolve += AppDomain_AssemblyResolve; Fonlow.TypeScriptCodeDom.TsCodeGenerationOptions.Instance.CamelCase = true; PocoAssemblyFileWalker.Walk(assemblyName, tsFileName, methods, ".Client", true); }
public void CreateCodeDom(Assembly assembly, CherryPickingMethods methods, DocCommentLookup docLookup, ModelGenOutputs codeGenOutputs) { this.docLookup = docLookup; this.settings = codeGenOutputs; var cherryTypes = PodGenHelper.GetCherryTypes(assembly, methods); CreateCodeDom(cherryTypes, methods, settings.CSClientNamespaceSuffix); }
public void CreateCodeDom(Assembly assembly, CherryPickingMethods methods, DocCommentLookup docLookup, string clientNamespaceSuffix) { this.docLookup = docLookup; this.clientNamespaceSuffix = clientNamespaceSuffix; var cherryTypes = PodGenHelper.GetCherryTypes(assembly, methods); CreateCodeDom(cherryTypes, methods, clientNamespaceSuffix); }
public void CreateCodeDom(Assembly assembly, CherryPickingMethods methods, DocCommentLookup docLookup, string clientNamespaceSuffix, bool dataAnnotationsEnabled, bool dataAnnotationsToComments) { this.docLookup = docLookup; this.clientNamespaceSuffix = clientNamespaceSuffix; this.dataAnnotationsEnabled = dataAnnotationsEnabled; this.dataAnnotationsToComments = dataAnnotationsToComments; var cherryTypes = PodGenHelper.GetCherryTypes(assembly, methods); CreateCodeDom(cherryTypes, methods, clientNamespaceSuffix); }
/// <summary> /// Walk classes in the assembly decorated by cherry picking data annotation attributes, and save TypeScript codes to the file. /// </summary> /// <param name="assemblyFilePath">Absolute or relative path, including the assembly file extension name dll or exe.</param> /// <param name="tsFilePath"></param> /// <param name="methods"></param> public static void Walk(string assemblyFilePath, string tsFilePath, CherryPickingMethods methods, string clientNamespaceSuffix) { var absolutePath = System.IO.Path.GetFullPath(assemblyFilePath); var assembly = LoadAssembly(absolutePath); if (assembly == null) { return; } var lookup = Fonlow.DocComment.DocCommentLookup.Create(DocComment.DocCommentLookup.GetXmlPath(assembly)); var gen = new Poco2TsGen(); gen.CreateCodeDom(assembly, methods, lookup, clientNamespaceSuffix); gen.SaveCodeToFile(tsFilePath); var msg = $"{tsFilePath} is generated."; Console.WriteLine(msg); Trace.WriteLine(msg); }
internal static Type[] GetCherryTypes(Assembly assembly, CherryPickingMethods methods) { try { return(assembly.GetTypes().Where(type => (TypeHelper.IsClassOrStruct(type) || type.IsEnum) && CherryPicking.IsCherryType(type, methods)).ToArray()); } catch (ReflectionTypeLoadException e) { foreach (Exception ex in e.LoaderExceptions) { Trace.TraceWarning(String.Format("When loading {0}, GetTypes errors occur: {1}", assembly.FullName, ex.Message)); } } catch (TargetInvocationException e) { Trace.TraceWarning(String.Format("When loading {0}, GetTypes errors occur: {1}", assembly.FullName, e.Message + "~~" + e.InnerException.Message)); } return(null); }
/// <summary> /// Create TypeScript CodeDOM for POCO types. /// For an enum type, all members will be processed regardless of EnumMemberAttribute. /// </summary> /// <param name="types">POCO types.</param> /// <param name="methods">How to cherry pick data to be exposed to the clients.</param> /// <param name="clientNamespaceSuffix"></param> public void CreateCodeDom(Type[] types, CherryPickingMethods methods, string clientNamespaceSuffix) { if (types == null) { throw new ArgumentNullException(nameof(types), "types is not defined."); } this.pendingTypes.AddRange(types); var typeGroupedByNamespace = types .GroupBy(d => d.Namespace) .OrderBy(k => k.Key); // order by namespace var namespacesOfTypes = typeGroupedByNamespace.Select(d => d.Key).ToArray(); foreach (var groupedTypes in typeGroupedByNamespace) { var clientNamespaceText = (groupedTypes.Key + clientNamespaceSuffix); var clientNamespace = new CodeNamespace(clientNamespaceText); codeCompileUnit.Namespaces.Add(clientNamespace); //namespace added to Dom Debug.WriteLine("Generating types in namespace: " + groupedTypes.Key + " ..."); groupedTypes.OrderBy(t => t.Name).Select(type => { var tsName = type.Name; Debug.WriteLine("clientClass: " + clientNamespace + " " + tsName); CodeTypeDeclaration typeDeclaration; if (TypeHelper.IsClassOrStruct(type)) { if (type.IsGenericType) { typeDeclaration = PodGenHelper.CreatePodClientGenericClass(clientNamespace, type); } else { typeDeclaration = type.IsClass ? PodGenHelper.CreatePodClientClass(clientNamespace, tsName) : PodGenHelper.CreatePodClientStruct(clientNamespace, tsName); } if (!type.IsValueType) { if (namespacesOfTypes.Contains(type.BaseType.Namespace)) { typeDeclaration.BaseTypes.Add(RefineCustomComplexTypeText(type.BaseType)); } else { typeDeclaration.BaseTypes.Add(type.BaseType); } } CreateTypeDocComment(type, typeDeclaration); var typeCherryMethods = CherryPicking.GetTypeCherryMethods(type); bool withDataContract = (typeCherryMethods & CherryPickingMethods.DataContract) == CherryPickingMethods.DataContract; var typeProperties = type.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public).OrderBy(p => p.Name).ToArray(); foreach (var propertyInfo in typeProperties) { var cherryType = CherryPicking.GetMemberCherryType(propertyInfo, methods, withDataContract); if (cherryType == CherryType.None) { continue; } string tsPropertyName; //todo: Maybe the required of JsonMemberAttribute? var isRequired = cherryType == CherryType.BigCherry; tsPropertyName = propertyInfo.Name; //todo: String.IsNullOrEmpty(dataMemberAttribute.Name) ? propertyInfo.Name : dataMemberAttribute.Name; Debug.WriteLine(String.Format("{0} : {1}", tsPropertyName, propertyInfo.PropertyType.Name)); var defaultValue = GetDefaultValue(propertyInfo.GetCustomAttribute(typeOfDefaultValueAttribute) as DefaultValueAttribute); //var clientProperty = new CodeMemberProperty() //orthodox way of creating property, but resulting in verbose generated codes //{ // Name = tsPropertyName, // Type = TranslateToClientTypeReference(propertyInfo.PropertyType), // Attributes = MemberAttributes.Public | MemberAttributes.Final, //}; var clientProperty = CreateProperty(tsPropertyName, propertyInfo.PropertyType, defaultValue); //hacky way of creating clean getter and writter. var isRequired = cherryType == CherryType.BigCherry; if (isRequired) { clientProperty.CustomAttributes.Add(new CodeAttributeDeclaration("System.ComponentModel.DataAnnotations.RequiredAttribute")); } //var privateFieldName = "_" + tsPropertyName; //typeDeclaration.Members.Add(new CodeMemberField() //{ // Name = privateFieldName, // Type = TranslateToClientTypeReference(propertyInfo.PropertyType), //}); //clientProperty.GetStatements.Add(new CodeSnippetStatement($"\t\t\t\treturn {privateFieldName};")); //clientProperty.SetStatements.Add(new CodeSnippetStatement($"\t\t\t\t{privateFieldName} = value;")); if (settings.DataAnnotationsEnabled) { AddValidationAttributes(propertyInfo, clientProperty, isRequired); } CreatePropertyDocComment(propertyInfo, clientProperty); if (settings.DecorateDataModelWithDataContract) { clientProperty.CustomAttributes.Add(new CodeAttributeDeclaration("System.Runtime.Serialization.DataMember")); } typeDeclaration.Members.Add(clientProperty); } var typeFields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public).OrderBy(f => f.Name).ToArray(); foreach (var fieldInfo in typeFields) { var cherryType = CherryPicking.GetMemberCherryType(fieldInfo, methods, withDataContract); if (cherryType == CherryType.None) { continue; } string tsPropertyName; tsPropertyName = fieldInfo.Name; //todo: String.IsNullOrEmpty(dataMemberAttribute.Name) ? propertyInfo.Name : dataMemberAttribute.Name; Debug.WriteLine(String.Format("{0} : {1}", tsPropertyName, fieldInfo.FieldType.Name)); var defaultValue = GetDefaultValue(fieldInfo.GetCustomAttribute(typeOfDefaultValueAttribute) as DefaultValueAttribute); //public fields of a class will be translated into properties if (type.IsClass) { //var clientProperty = new CodeMemberProperty() //orthodox way of creating property, but resulting in verbose generated codes //{ // Name = tsPropertyName, // Type = TranslateToClientTypeReference(fieldInfo.FieldType), // Attributes = MemberAttributes.Public | MemberAttributes.Final, //}; var clientProperty = CreateProperty(tsPropertyName, fieldInfo.FieldType, defaultValue); //hacky way of creating clean getter and writter. var isRequired = cherryType == CherryType.BigCherry; if (isRequired) { clientProperty.CustomAttributes.Add(new CodeAttributeDeclaration("System.ComponentModel.DataAnnotations.RequiredAttribute")); } //var privateFieldName = "_" + tsPropertyName; //typeDeclaration.Members.Add(new CodeMemberField() //{ // Name = privateFieldName, // Type = TranslateToClientTypeReference(fieldInfo.FieldType), //}); //clientProperty.GetStatements.Add(new CodeSnippetStatement($"\t\t\t\treturn {privateFieldName};")); //clientProperty.SetStatements.Add(new CodeSnippetStatement($"\t\t\t\t{privateFieldName} = value;")); if (settings.DataAnnotationsEnabled) { AddValidationAttributes(fieldInfo, clientProperty, isRequired); } CreateFieldDocComment(fieldInfo, clientProperty); if (settings.DecorateDataModelWithDataContract) { clientProperty.CustomAttributes.Add(new CodeAttributeDeclaration("System.Runtime.Serialization.DataMember")); } typeDeclaration.Members.Add(clientProperty); } else //public fields of struct { var clientField = new CodeMemberField() { Name = tsPropertyName, Type = TranslateToClientTypeReference(fieldInfo.FieldType), Attributes = MemberAttributes.Public | MemberAttributes.Final, //todo: add some attributes }; CreateFieldDocComment(fieldInfo, clientField); if (settings.DecorateDataModelWithDataContract) { clientField.CustomAttributes.Add(new CodeAttributeDeclaration("System.Runtime.Serialization.DataMember")); } typeDeclaration.Members.Add(clientField); } } if (settings.DecorateDataModelWithDataContract) { typeDeclaration.CustomAttributes.Add(new CodeAttributeDeclaration("System.Runtime.Serialization.DataContract", new CodeAttributeArgument("Namespace", new CodeSnippetExpression($"\"{settings.DataContractNamespace}\"")))); } if (settings.DecorateDataModelWithSerializable) { typeDeclaration.CustomAttributes.Add(new CodeAttributeDeclaration("System.SerializableAttribute")); } } else if (type.IsEnum) { typeDeclaration = PodGenHelper.CreatePodClientEnum(clientNamespace, tsName); CreateTypeDocComment(type, typeDeclaration); int k = 0; foreach (var fieldInfo in type.GetFields(BindingFlags.Public | BindingFlags.Static)) //not to sort { var name = fieldInfo.Name; var intValue = (int)Convert.ChangeType(fieldInfo.GetValue(null), typeof(int)); Debug.WriteLine(name + " -- " + intValue); var isInitialized = intValue != k; var clientField = new CodeMemberField() { Name = name, Type = new CodeTypeReference(fieldInfo.FieldType), InitExpression = isInitialized ? new CodePrimitiveExpression(intValue) : null, }; CreateFieldDocComment(fieldInfo, clientField); if (settings.DecorateDataModelWithDataContract) { clientField.CustomAttributes.Add(new CodeAttributeDeclaration("System.Runtime.Serialization.EnumMemberAttribute")); } typeDeclaration.Members.Add(clientField); k++; } if (settings.DecorateDataModelWithDataContract) { typeDeclaration.CustomAttributes.Add(new CodeAttributeDeclaration("System.Runtime.Serialization.DataContract", new CodeAttributeArgument("Namespace", new CodeSnippetExpression($"\"{settings.DataContractNamespace}\"")))); } if (settings.DecorateDataModelWithSerializable) { typeDeclaration.CustomAttributes.Add(new CodeAttributeDeclaration("System.SerializableAttribute")); } } else { Trace.TraceWarning("Not yet supported: " + type.Name); typeDeclaration = null; } return(typeDeclaration); } ).ToArray();//add classes into the namespace } }
/// <summary> /// Create TypeScript CodeDOM for POCO types. /// For an enum type, all members will be processed regardless of EnumMemberAttribute. /// </summary> /// <param name="types">POCO types.</param> /// <param name="methods"></param> public void CreateCodeDom(Type[] types, CherryPickingMethods methods) { if (types == null) { throw new ArgumentNullException("types", "types is not defined."); } this.pendingTypes.AddRange(types); var typeGroupedByNamespace = types .GroupBy(d => d.Namespace) .OrderBy(k => k.Key); // order by namespace var namespacesOfTypes = typeGroupedByNamespace.Select(d => d.Key).ToArray(); foreach (var groupedTypes in typeGroupedByNamespace) { var clientNamespaceText = (groupedTypes.Key + ".Client").Replace('.', '_'); var clientNamespace = new CodeNamespace(clientNamespaceText); targetUnit.Namespaces.Add(clientNamespace); //namespace added to Dom Debug.WriteLine("Generating types in namespace: " + groupedTypes.Key + " ..."); groupedTypes.OrderBy(t => t.Name).Select(type => { var tsName = type.Name; Debug.WriteLine("tsClass: " + clientNamespace + " " + tsName); CodeTypeDeclaration typeDeclaration; if (TypeHelper.IsClassOrStruct(type)) { if (type.IsGenericType) { typeDeclaration = PodGenHelper.CreatePodClientGenericInterface(clientNamespace, type); } else { typeDeclaration = PodGenHelper.CreatePodClientInterface(clientNamespace, tsName); } if (!type.IsValueType) { if (namespacesOfTypes.Contains(type.BaseType.Namespace)) { typeDeclaration.BaseTypes.Add(RefineCustomComplexTypeText(type.BaseType)); } else { typeDeclaration.BaseTypes.Add(type.BaseType); } } CreateTypeDocComment(type, typeDeclaration); var typeProperties = type.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public).OrderBy(p => p.Name).ToArray(); foreach (var propertyInfo in typeProperties) { var cherryType = CherryPicking.GetMemberCherryType(propertyInfo, methods); if (cherryType == CherryType.None) { continue; } string tsPropertyName; var isRequired = cherryType == CherryType.BigCherry; var customName = CherryPicking.GetFieldCustomName(propertyInfo, methods); if (String.IsNullOrEmpty(customName)) { tsPropertyName = Fonlow.TypeScriptCodeDom.TsCodeGenerationOptions.Instance.CamelCase ? Fonlow.Text.StringExtensions.ToCamelCase(propertyInfo.Name) : propertyInfo.Name; } else { tsPropertyName = customName; } Debug.WriteLine(String.Format("{0} : {1}", tsPropertyName, propertyInfo.PropertyType.Name)); var clientField = new CodeMemberField() //Yes, clr property translated to ts field { Name = tsPropertyName + (isRequired ? String.Empty : "?"), Type = TranslateToClientTypeReference(propertyInfo.PropertyType), // Attributes = MemberAttributes.Public, }; CreatePropertyDocComment(propertyInfo, clientField); typeDeclaration.Members.Add(clientField); } var typeFields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public).OrderBy(f => f.Name).ToArray(); foreach (var fieldInfo in typeFields) { var cherryType = CherryPicking.GetMemberCherryType(fieldInfo, methods); if (cherryType == CherryType.None) { continue; } string tsPropertyName; var isRequired = (cherryType == CherryType.BigCherry) || !type.IsClass; //public fields in struct should all be value types, so required var customName = CherryPicking.GetFieldCustomName(fieldInfo, methods); if (String.IsNullOrEmpty(customName)) { tsPropertyName = Fonlow.TypeScriptCodeDom.TsCodeGenerationOptions.Instance.CamelCase ? Fonlow.Text.StringExtensions.ToCamelCase(fieldInfo.Name) : fieldInfo.Name; } else { tsPropertyName = customName; } Debug.WriteLine(String.Format("{0} : {1}", tsPropertyName, fieldInfo.FieldType.Name)); var clientField = new CodeMemberField() { Name = tsPropertyName + (isRequired ? String.Empty : "?"), Type = TranslateToClientTypeReference(fieldInfo.FieldType), }; CreateFieldDocComment(fieldInfo, clientField); typeDeclaration.Members.Add(clientField); } } else if (type.IsEnum) { typeDeclaration = PodGenHelper.CreatePodClientEnum(clientNamespace, tsName); CreateTypeDocComment(type, typeDeclaration); int k = 0; foreach (var fieldInfo in type.GetFields(BindingFlags.Public | BindingFlags.Static)) { var name = fieldInfo.Name; var intValue = (int)Convert.ChangeType(fieldInfo.GetValue(null), typeof(int)); Debug.WriteLine(name + " -- " + intValue); var isInitialized = intValue != k; var clientField = new CodeMemberField() { Name = name, Type = new CodeTypeReference(fieldInfo.FieldType), InitExpression = isInitialized ? new CodePrimitiveExpression(intValue) : null, }; CreateFieldDocComment(fieldInfo, clientField); typeDeclaration.Members.Add(clientField); k++; } } else { Trace.TraceWarning("Not yet supported: " + type.Name); typeDeclaration = null; } return(typeDeclaration); } ).ToArray();//add classes into the namespace } }
/// <summary> /// Create TypeScript CodeDOM for POCO types. /// For an enum type, all members will be processed regardless of EnumMemberAttribute. /// </summary> /// <param name="types">POCO types.</param> /// <param name="methods">How to cherry pick data to be exposed to the clients.</param> public void CreateCodeDom(Type[] types, CherryPickingMethods methods) { if (types == null) { throw new ArgumentNullException("types", "types is not defined."); } this.pendingTypes.AddRange(types); var typeGroupedByNamespace = types.GroupBy(d => d.Namespace); var namespacesOfTypes = typeGroupedByNamespace.Select(d => d.Key).ToArray(); foreach (var groupedTypes in typeGroupedByNamespace) { var clientNamespaceText = (groupedTypes.Key + ".Client"); var clientNamespace = new CodeNamespace(clientNamespaceText); targetUnit.Namespaces.Add(clientNamespace);//namespace added to Dom Debug.WriteLine("Generating types in namespace: " + groupedTypes.Key + " ..."); groupedTypes.Select(type => { var tsName = type.Name; Debug.WriteLine("clientClass: " + clientNamespace + " " + tsName); CodeTypeDeclaration typeDeclaration; if (TypeHelper.IsClassOrStruct(type)) { typeDeclaration = type.IsClass ? PodGenHelper.CreatePodClientClass(clientNamespace, tsName): PodGenHelper.CreatePodClientStruct(clientNamespace, tsName); if (!type.IsValueType) { if (namespacesOfTypes.Contains(type.BaseType.Namespace)) { typeDeclaration.BaseTypes.Add(RefineCustomComplexTypeText(type.BaseType)); } else { typeDeclaration.BaseTypes.Add(type.BaseType); } } CreateTypeDocComment(type, typeDeclaration); foreach (var propertyInfo in type.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public)) { var cherryType = CherryPicking.GetMemberCherryType(propertyInfo, methods); if (cherryType == CherryType.None) { continue; } string tsPropertyName; //todo: Maybe the required of JsonMemberAttribute? var isRequired = cherryType == CherryType.BigCherry; tsPropertyName = propertyInfo.Name;//todo: String.IsNullOrEmpty(dataMemberAttribute.Name) ? propertyInfo.Name : dataMemberAttribute.Name; Debug.WriteLine(String.Format("{0} : {1}", tsPropertyName, propertyInfo.PropertyType.Name)); var clientProperty = new CodeMemberProperty() { Name = tsPropertyName, Type = TranslateToClientTypeReference(propertyInfo.PropertyType), Attributes = MemberAttributes.Public | MemberAttributes.Final, //todo: add some attributes }; var isRequired = cherryType == CherryType.BigCherry; if (isRequired) { clientProperty.CustomAttributes.Add(new CodeAttributeDeclaration("System.ComponentModel.DataAnnotations.RequiredAttribute")); } var privateFieldName = "_" + tsPropertyName; typeDeclaration.Members.Add(new CodeMemberField() { Name = privateFieldName, Type = TranslateToClientTypeReference(propertyInfo.PropertyType), }); clientProperty.GetStatements.Add(new CodeSnippetStatement($" return {privateFieldName};")); clientProperty.SetStatements.Add(new CodeSnippetStatement($" {privateFieldName} = value;")); CreatePropertyDocComment(propertyInfo, clientProperty); typeDeclaration.Members.Add(clientProperty); } foreach (var fieldInfo in type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public)) { var cherryType = CherryPicking.GetMemberCherryType(fieldInfo, methods); if (cherryType == CherryType.None) { continue; } string tsPropertyName; tsPropertyName = fieldInfo.Name;//todo: String.IsNullOrEmpty(dataMemberAttribute.Name) ? propertyInfo.Name : dataMemberAttribute.Name; Debug.WriteLine(String.Format("{0} : {1}", tsPropertyName, fieldInfo.FieldType.Name)); //public fields of a class will be translated into properties if (type.IsClass) { var clientProperty = new CodeMemberProperty() { Name = tsPropertyName, Type = TranslateToClientTypeReference(fieldInfo.FieldType), Attributes = MemberAttributes.Public | MemberAttributes.Final, //todo: add some attributes }; var isRequired = cherryType == CherryType.BigCherry; if (isRequired) { clientProperty.CustomAttributes.Add(new CodeAttributeDeclaration("System.ComponentModel.DataAnnotations.RequiredAttribute")); } var privateFieldName = "_" + tsPropertyName; typeDeclaration.Members.Add(new CodeMemberField() { Name = privateFieldName, Type = TranslateToClientTypeReference(fieldInfo.FieldType), }); clientProperty.GetStatements.Add(new CodeSnippetStatement($" return {privateFieldName};")); clientProperty.SetStatements.Add(new CodeSnippetStatement($" {privateFieldName} = value;")); CreateFieldDocComment(fieldInfo, clientProperty); typeDeclaration.Members.Add(clientProperty); } else //public fields of struct { var clientField = new CodeMemberField() { Name = tsPropertyName, Type = TranslateToClientTypeReference(fieldInfo.FieldType), Attributes = MemberAttributes.Public | MemberAttributes.Final, //todo: add some attributes }; CreateFieldDocComment(fieldInfo, clientField); typeDeclaration.Members.Add(clientField); } } } else if (type.IsEnum) { typeDeclaration = PodGenHelper.CreatePodClientEnum(clientNamespace, tsName); CreateTypeDocComment(type, typeDeclaration); int k = 0; foreach (var fieldInfo in type.GetFields(BindingFlags.Public | BindingFlags.Static)) { var name = fieldInfo.Name; var intValue = (int)Convert.ChangeType(fieldInfo.GetValue(null), typeof(int)); Debug.WriteLine(name + " -- " + intValue); var isInitialized = intValue != k; var clientField = new CodeMemberField() { Name = name, Type = new CodeTypeReference(fieldInfo.FieldType), InitExpression = isInitialized ? new CodePrimitiveExpression(intValue) : null, }; CreateFieldDocComment(fieldInfo, clientField); typeDeclaration.Members.Add(clientField); k++; } } else { Trace.TraceWarning("Not yet supported: " + type.Name); typeDeclaration = null; } return(typeDeclaration); } ).ToArray();//add classes into the namespace } }
public static CherryType GetMemberCherryType(MemberInfo memberInfo, CherryPickingMethods methods, bool typeIsWithDataContract) { CherryType[] r = { CherryType.None, CherryType.None, CherryType.None, CherryType.None, CherryType.None }; //opt-in for DataContract through DataMemberAttribute , and the type may or may not be decorated by DataContractAttribute. // Enum will have all member fields being picked, regardless of the EnumMemberAttribute. if ((methods & CherryPickingMethods.DataContract) == CherryPickingMethods.DataContract) { var a = TypeHelper.ReadAttribute <DataMemberAttribute>(memberInfo); if (a == null) { r[1] = CherryType.None; } else { r[1] = a.IsRequired ? CherryType.BigCherry : CherryType.Cherry; } if (typeIsWithDataContract) { return(r[1]); } } //opt-in for NewtonsoftJson through JsonPropertyAttribute, , and the type may or may not be decorated by JsonObjectAttribute. if ((methods & CherryPickingMethods.NewtonsoftJson) == CherryPickingMethods.NewtonsoftJson) { var a = TypeHelper.AttributeExists(memberInfo, "Newtonsoft.Json.JsonIgnoreAttribute"); if (a == null) { var a2 = TypeHelper.ReadAttribute <Newtonsoft.Json.JsonPropertyAttribute>(memberInfo); if (a2 != null) { r[2] = TypeHelper.GetRequired(a2, "Required", "Default") ? CherryType.BigCherry : CherryType.Cherry; } else { r[2] = CherryType.Cherry; } } else { r[2] = CherryType.None; } } //opt-out for Serializable through NonSerializedAttribute if ((methods & CherryPickingMethods.Serializable) == CherryPickingMethods.Serializable) { var a = TypeHelper.ReadAttribute <NonSerializedAttribute>(memberInfo); if (a == null) { var a2 = TypeHelper.ReadAttribute <RequiredAttribute>(memberInfo); r[3] = a2 == null ? CherryType.Cherry : CherryType.BigCherry; } else { r[3] = CherryType.None; } } //opt-out for AspNet if ((methods & CherryPickingMethods.AspNet) == CherryPickingMethods.AspNet) { var a = TypeHelper.ReadAttribute <RequiredAttribute>(memberInfo); r[4] = a == null ? CherryType.Cherry : CherryType.BigCherry; } //opt-out if (methods == CherryPickingMethods.All) { r[0] = CherryType.Cherry; } return(r.Max()); }