示例#1
0
        public void CreateCodeDom(Assembly assembly, CherryPickingMethods methods, DocCommentLookup docLookup)
        {
            this.docLookup = docLookup;
            var cherryTypes = PodGenHelper.GetCherryTypes(assembly, methods);

            CreateCodeDom(cherryTypes, methods);
        }
示例#2
0
        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);
        }
示例#3
0
        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));
        }
示例#4
0
        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));
        }
示例#5
0
        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));
            }
        }
示例#6
0
        /// <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
            }
        }
示例#7
0
        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);
        }