public void CreateCodeDom(Assembly assembly, CherryPickingMethods methods, DocCommentLookup docLookup) { this.docLookup = docLookup; var cherryTypes = PodGenHelper.GetCherryTypes(assembly, methods); CreateCodeDom(cherryTypes, methods); }
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); }
CodeMemberField GenerateCasualEnumForProperty(OpenApiSchema propertySchema, string typeDeclarationName, string propertyName, string ns, bool isRequired) { string casualEnumName = typeDeclarationName + NameFunc.RefinePropertyName(propertyName); // make Pascal case like OrderStatus CodeTypeDeclaration existingType = FindTypeDeclarationInNamespaces(casualEnumName, ns); if (existingType == null) { CodeTypeDeclaration casualEnumTypeDeclaration = PodGenHelper.CreatePodClientEnum(ClientNamespace, casualEnumName); AddEnumMembers(casualEnumTypeDeclaration, propertySchema.Enum); Trace.TraceInformation($"Casual enum {casualEnumName} added for {typeDeclarationName}/{propertyName}."); } return(CreateProperty(propertyName, casualEnumName, isRequired)); }
public Tuple <CodeTypeReference, CodeTypeDeclaration> GenerateCasualEnum(OpenApiSchema propertySchema, string typeDeclarationName, string propertyName, string ns) { string casualEnumName = typeDeclarationName + NameFunc.RefinePropertyName(propertyName); CodeTypeDeclaration existingType = FindTypeDeclarationInNamespaces(casualEnumName, ns); CodeTypeDeclaration casualEnumTypeDeclaration = null; if (existingType == null) { casualEnumTypeDeclaration = PodGenHelper.CreatePodClientEnum(ClientNamespace, casualEnumName); AddEnumMembers(casualEnumTypeDeclaration, propertySchema.Enum); Trace.TraceInformation($"Casual enum {casualEnumName} added for {typeDeclarationName}/{propertyName}."); } CodeTypeReference codeTypeReference = ComponentsHelper.TranslateTypeNameToClientTypeReference(casualEnumName); return(Tuple.Create(codeTypeReference, casualEnumTypeDeclaration)); }
public override CodeTypeDeclaration AddTypeToClassNamespace(string typeName, string ns) { if (String.IsNullOrEmpty(ns)) { return(PodGenHelper.CreatePodClientInterface(ClientNamespace, typeName)); } else { var foundNamespace = ClassNamespaces.Find(d => d.Name == ns); if (foundNamespace == null) { foundNamespace = new CodeNamespace(ns); codeCompileUnit.Namespaces.Add(foundNamespace); ClassNamespaces.Add(foundNamespace); } return(PodGenHelper.CreatePodClientInterface(foundNamespace, typeName)); } }
/// <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 } }
public override void AddTypeToCodeDom(KeyValuePair <string, OpenApiSchema> item) { var ns = NameFunc.GetNamespaceOfClassName(item.Key); var currentTypeName = NameFunc.RefineTypeName(item.Key, ns); RegisterSchemaRefIdToBeAdded(item.Key); OpenApiSchema schema = item.Value; string type = schema.Type; IList <OpenApiSchema> allOfBaseTypeSchemaList = schema.AllOf; //maybe empty IList <IOpenApiAny> enumTypeList = schema.Enum; //maybe empty bool isForClass = enumTypeList.Count == 0; CodeTypeDeclaration typeDeclaration = null; if (isForClass) { if (schema.Properties.Count > 0 || (schema.Properties.Count == 0 && allOfBaseTypeSchemaList.Count > 1)) { typeDeclaration = AddTypeToClassNamespace(currentTypeName, ns); if (String.IsNullOrEmpty(type) && allOfBaseTypeSchemaList.Count > 0) { OpenApiSchema allOfRef = allOfBaseTypeSchemaList[0]; if (allOfRef.Reference == null) { Trace.TraceWarning($"Not yet support Type {item.Key} having allOf[0] without Reference. Skipped."); RemoveRegisteredSchemaRefId(item.Key); return; } string baseTypeName = NameFunc.RefineTypeName(allOfRef.Reference.Id, ns); //pointing to parent class typeDeclaration.BaseTypes.Add(baseTypeName); if (allOfBaseTypeSchemaList.Count > 1) { OpenApiSchema allOfProperteisSchema = allOfBaseTypeSchemaList[1]; //the 2nd one points to properties of the derived type, while the 1st one points to the base type. AddProperties(typeDeclaration, allOfProperteisSchema, currentTypeName, ns); } } CreateTypeDocComment(item, typeDeclaration); AddProperties(typeDeclaration, schema, currentTypeName, ns); } else if (type == "array") // wrapper of array { OpenApiReference itemsRef = schema.Items.Reference; if (itemsRef == null) //Array type with casual schema { if (schema.Items.Properties.Count > 0) //casual member type definition in an array type { var newTypeName = currentTypeName + "Element"; if (FindTypeDeclarationInNamespaces(newTypeName, ns) == null) { AddTypeToCodeDom(new KeyValuePair <string, OpenApiSchema>(newTypeName, schema.Items)); //so add casual type recursively TypeAliasDic.Add(item.Key, $"{newTypeName}[]"); Trace.TraceInformation($"TypeAliasDic.Add({item.Key}, {newTypeName}[]) -- generated: {newTypeName}"); } } else { RemoveRegisteredSchemaRefId(item.Key); Trace.TraceWarning($"Not yet support array type with casual items type without reference and without casual properties: {item.Key}. Skipped."); } return; } string typeNs = NameFunc.GetNamespaceOfClassName(itemsRef.Id); string typeName = NameFunc.RefineTypeName(itemsRef.Id, typeNs); var existing = FindTypeDeclarationInNamespaces(typeName, typeNs); if (existing == null) //so process itemsRef.Id first before considering type alias { AddTypeToCodeDom(new KeyValuePair <string, OpenApiSchema>(itemsRef.Id, FindSchema(itemsRef.Id))); RemoveRegisteredSchemaRefId(itemsRef.Id); } //Array type with ref to the other type if (TypeAliasDic.TryGet(itemsRef.Id, out string arrayTypeAlias)) { TypeAliasDic.Add(item.Key, $"{arrayTypeAlias}[]"); Trace.TraceInformation($"TypeAliasDic.Add({item.Key}, {arrayTypeAlias}[]) with existing ({itemsRef.Id}, {arrayTypeAlias})"); } else { TypeAliasDic.Add(item.Key, $"{itemsRef.Id}[]"); Trace.TraceInformation($"TypeAliasDic.Add({item.Key}, {itemsRef.Id}[])"); } } else if (type != "object" && !String.IsNullOrEmpty(type)) { var clrType = TypeRefHelper.PrimitiveSwaggerTypeToClrType(type, null); TypeAliasDic.Add(item.Key, clrType.FullName); Trace.TraceInformation($"TypeAliasDic.Add({item.Key}, {clrType.FullName}) -- clrType: {clrType.FullName}"); } else if (type == "object" || String.IsNullOrEmpty(type)) //object alias without properties { typeDeclaration = AddTypeToClassNamespace(currentTypeName, ns); CreateTypeDocComment(item, typeDeclaration); } else { Trace.TraceInformation($"Type Alias {item.Key} for type {type} is skipped."); RemoveRegisteredSchemaRefId(item.Key); return; } if (typeDeclaration != null) { Trace.TraceInformation($"TS clientClass {currentTypeName} created for {item.Key}"); } else { Trace.TraceInformation($"TS Candidate clientClass {currentTypeName} for {item.Key} is skipped"); } } else { typeDeclaration = PodGenHelper.CreatePodClientEnum(ClientNamespace, currentTypeName); CreateTypeDocComment(item, typeDeclaration); AddEnumMembers(typeDeclaration, enumTypeList); Trace.TraceInformation("TS client enum: " + currentTypeName); } RemoveRegisteredSchemaRefId(item.Key); }
/// <summary> /// The Id will be translated to proper C# type name and namespace if the YAML does support namespace in components. /// </summary> /// <param name="item">Reference Id and its schema</param> public override void AddTypeToCodeDom(KeyValuePair <string, OpenApiSchema> item) { string ns = NameFunc.GetNamespaceOfClassName(item.Key); string currentTypeName = NameFunc.RefineTypeName(item.Key, ns); RegisterSchemaRefIdToBeAdded(item.Key); OpenApiSchema schema = item.Value; string type = schema.Type; IList <OpenApiSchema> allOfBaseTypeSchemaList = schema.AllOf; //maybe empty IList <IOpenApiAny> enumTypeList = schema.Enum; //maybe empty bool isForClass = enumTypeList.Count == 0; CodeTypeDeclaration typeDeclaration = null; if (isForClass) { if (schema.Properties.Count > 0 || (schema.Properties.Count == 0 && allOfBaseTypeSchemaList.Count > 1)) { typeDeclaration = AddTypeToClassNamespace(currentTypeName, ns); if (String.IsNullOrEmpty(type) && allOfBaseTypeSchemaList.Count > 0) { OpenApiSchema allOfRef = allOfBaseTypeSchemaList[0]; if (allOfRef.Reference == null) { Trace.TraceWarning($"Not yet support Type {item.Key} having allOf[0] without Reference. Skipped."); RemoveRegisteredSchemaRefId(item.Key); return; } string baseTypeName = NameFunc.RefineTypeName(allOfRef.Reference.Id, ns); //pointing to parent class typeDeclaration.BaseTypes.Add(baseTypeName); if (allOfBaseTypeSchemaList.Count > 1) { OpenApiSchema allOfProperteisSchema = allOfBaseTypeSchemaList[1]; //the 2nd one points to properties of the derived type, while the 1st one points to the base type. AddProperties(typeDeclaration, allOfProperteisSchema, currentTypeName, ns); } } CreateTypeDocComment(item, typeDeclaration); AddProperties(typeDeclaration, schema, currentTypeName, ns); 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 == "array") // wrapper of array. Microsoft OpenApi library could not intepret this as type alias, so I have to register the alias myself. { OpenApiReference itemsRef = schema.Items.Reference; if (itemsRef == null) //Array type with casual schema { if (schema.Items.Properties.Count > 0) //casual member type definition in an array type { string newTypeName = currentTypeName + "Element"; if (FindTypeDeclarationInNamespaces(newTypeName, ns) == null) { AddTypeToCodeDom(new KeyValuePair <string, OpenApiSchema>(newTypeName, schema.Items)); //so add casual type recursively var typeNameX = TypeRefHelper.ArrayAsIEnumerableDerivedToType(newTypeName, settings.ArrayAs); TypeAliasDic.Add(item.Key, typeNameX); Trace.TraceInformation($"TypeAliasDic.Add({item.Key}, {typeNameX}) -- generated: {newTypeName}"); } } else { RemoveRegisteredSchemaRefId(item.Key); Trace.TraceWarning($"Not yet support array type with casual items type without reference and without casual properties: {item.Key}. Skipped."); } return; } string typeNs = NameFunc.GetNamespaceOfClassName(itemsRef.Id); string typeName = NameFunc.RefineTypeName(itemsRef.Id, typeNs); CodeTypeDeclaration existing = FindTypeDeclarationInNamespaces(typeName, typeNs); if (existing == null) //so process itemsRef.Id first before considering type alias { AddTypeToCodeDom(new KeyValuePair <string, OpenApiSchema>(itemsRef.Id, FindSchema(itemsRef.Id))); RemoveRegisteredSchemaRefId(itemsRef.Id); } //Array type with ref to the other type if (TypeAliasDic.TryGet(itemsRef.Id, out string arrayTypeAlias)) { var typeNameX = TypeRefHelper.ArrayAsIEnumerableDerivedToType(arrayTypeAlias, settings.ArrayAs); TypeAliasDic.Add(item.Key, typeNameX); Trace.TraceInformation($"TypeAliasDic.Add({item.Key}, {typeNameX}) with existing ({itemsRef.Id}, {arrayTypeAlias})"); } else { var typeNameX = TypeRefHelper.ArrayAsIEnumerableDerivedToType(itemsRef.Id, settings.ArrayAs); TypeAliasDic.Add(item.Key, typeNameX); Trace.TraceInformation($"TypeAliasDic.Add({item.Key}, {typeNameX})"); } } else if (type != "object" && !String.IsNullOrEmpty(type)) { Type clrType = TypeRefHelper.PrimitiveSwaggerTypeToClrType(type, null); TypeAliasDic.Add(item.Key, clrType.FullName); Trace.TraceInformation($"TypeAliasDic.Add({item.Key}, {clrType.FullName}) -- clrType: {clrType.FullName}"); } else if (type == "object" || String.IsNullOrEmpty(type)) //object alias without properties { typeDeclaration = AddTypeToClassNamespace(currentTypeName, ns); CreateTypeDocComment(item, typeDeclaration); 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.TraceInformation($"Type Alias {item.Key} for type {type} is skipped."); RemoveRegisteredSchemaRefId(item.Key); return; } if (typeDeclaration != null) { Trace.TraceInformation($"clientClass {currentTypeName} created for {item.Key}"); } else { Trace.TraceInformation($"Candidate clientClass {currentTypeName} for {item.Key} is skipped"); } } else { typeDeclaration = PodGenHelper.CreatePodClientEnum(ClientNamespace, currentTypeName); CreateTypeDocComment(item, typeDeclaration); AddEnumMembers(typeDeclaration, enumTypeList); if (settings.DecorateDataModelWithDataContract) { typeDeclaration.CustomAttributes.Add(new CodeAttributeDeclaration("System.Runtime.Serialization.DataContract", new CodeAttributeArgument("Namespace", new CodeSnippetExpression($"\"{settings.DataContractNamespace}\"")))); //net 5.0 https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-customize-properties#enums-as-strings if (settings.EnumToString) { if (settings.UseSystemTextJson) { //[System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Serialization.JsonStringEnumConverter))] typeDeclaration.CustomAttributes.Add(new CodeAttributeDeclaration("System.Text.Json.Serialization.JsonConverter", new CodeAttributeArgument(new CodeSnippetExpression("typeof(System.Text.Json.Serialization.JsonStringEnumConverter)")))); } else { //[JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] typeDeclaration.CustomAttributes.Add(new CodeAttributeDeclaration("Newtonsoft.Json.JsonConverter", new CodeAttributeArgument(new CodeSnippetExpression("typeof(Newtonsoft.Json.Converters.StringEnumConverter)")))); } } } if (settings.DecorateDataModelWithSerializable) { typeDeclaration.CustomAttributes.Add(new CodeAttributeDeclaration("System.SerializableAttribute")); } Trace.TraceInformation("client enum: " + currentTypeName); } RemoveRegisteredSchemaRefId(item.Key); }