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">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 } }