Exemple #1
0
        public ParameterDescriptionEx[] OpenApiParametersToParameterDescriptions(IList <OpenApiParameter> ps)
        {
            return(ps.Select(p =>
            {
                var refinedName = NameFunc.RefineParameterName(p.Name);
                var r = new ParameterDescriptionEx()
                {
                    Name = refinedName,                     //azure.com\apimanagement-apimapis has $ in query parameter
                    QName = p.Name,
                    Documentation = p.Description,
                    ParameterDescriptor = new ParameterDescriptor()
                    {
                        IsOptional = !p.Required,
                        ParameterName = refinedName,
                        ParameterType = TypeRefHelper.PrimitiveSwaggerTypeToClrType(p.Schema.Type, p.Schema.Format),
                        ParameterBinder = ParameterLocationToParameterBinder(p.In),
                    },

                    ParameterTypeReference = OpenApiParameterToCodeTypeReference(p)
                };

                return r;
            }
                             ).Where(k => k.ParameterDescriptor.ParameterBinder != ParameterBinder.None).ToArray());
        }
Exemple #2
0
        public static string RefinePropertyName(string s)
        {
            if (String.IsNullOrEmpty(s))
            {
                return(s);
            }

            return(NameFunc.ReplaceDashToTitleCase((NameFunc.ToTitleCase(s.Replace("$", "").Replace(':', '_').Replace('-', '_').Replace('.', '_')
                                                                         .Replace('[', '_').Replace(']', '_').Replace('/', '_').Replace('#', '_').Replace('@', '_')
                                                                         .Replace(' ', '_')))));
        }
Exemple #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));
        }
Exemple #4
0
        public CodeTypeReference CreateComplexCodeTypeReference(OpenApiSchema propertySchema)
        {
            string propertyTypeNs = NameFunc.GetNamespaceOfClassName(propertySchema.Reference.Id);
            string complexType    = NameFunc.RefineTypeName(propertySchema.Reference.Id, propertyTypeNs);
            var    existingType   = FindTypeDeclarationInNamespaces(complexType, propertyTypeNs);

            if (existingType == null && !RegisteredSchemaRefIdExists(propertySchema.Reference.Id))             // Referencing to a type not yet added to namespace
            {
                AddTypeToCodeDom(new KeyValuePair <string, OpenApiSchema>(complexType, propertySchema));
            }

            var typeWithNs = NameFunc.CombineNamespaceWithClassName(propertyTypeNs, complexType);

            return(TypeRefHelper.TranslateToClientTypeReference(typeWithNs));
        }
        static string GetDefaultValue(OpenApiSchema s)
        {
            if (s.Default == null)
            {
                return(null);
            }

            if (s.Default is OpenApiString stringValue)
            {
                if (s.Enum == null || s.Enum.Count == 0)                 //Sometimes people make make a number default with value string. And this mistake seems common. Better to tolerate.
                {
                    if (s.Type == "string")
                    {
                        return("\"" + EscapeString(stringValue.Value) + "\"");
                    }

                    return(stringValue.Value);
                }
                else                 //enum
                {
                    return(NameFunc.RefineEnumValue(stringValue.Value));
                }
            }

            if (s.Default is OpenApiInteger integerValue)
            {
                return((s.Enum == null || s.Enum.Count == 0) ? integerValue.Value.ToString() : NameFunc.RefineEnumValue(integerValue.Value.ToString()));
            }

            if (s.Default is OpenApiBoolean boolValue)
            {
                return(boolValue.Value ? "true" : "false");
            }

            if (s.Default is OpenApiFloat floatValue)
            {
                return(floatValue.Value.ToString());
            }

            if (s.Default is OpenApiDouble doubleValue)
            {
                return(doubleValue.Value.ToString());
            }

            Trace.TraceWarning($"Default as {s.Default.GetType().FullName} is not yet supported.");
            return(null);
        }
        /// <summary>
        /// Translate OpenApiMediaType content to CodeTypeReference
        /// </summary>
        /// <param name="content"></param>
        /// <returns></returns>
        public static CodeTypeReference OpenApiMediaTypeToCodeTypeReference(OpenApiMediaType content)
        {
            if (content.Schema == null)
            {
                throw new ArgumentException("Content has no Schema", nameof(content));
            }

            string schemaType = content.Schema.Type;

            if (schemaType != null)
            {
                if (schemaType == "array")                 // for array
                {
                    OpenApiSchema arrayItemsSchema = content.Schema.Items;
                    if (arrayItemsSchema.Reference != null)                     //array of custom type
                    {
                        string            ns                     = NameFunc.GetNamespaceOfClassName(arrayItemsSchema.Reference.Id);
                        string            arrayTypeName          = NameFunc.RefineTypeName(arrayItemsSchema.Reference.Id, ns);
                        CodeTypeReference arrayCodeTypeReference = CreateArrayOfCustomTypeReference(CombineNamespaceWithClassName(ns, arrayTypeName), 1);
                        return(arrayCodeTypeReference);
                    }
                    else
                    {
                        string            arrayType = arrayItemsSchema.Type;
                        Type              clrType   = PrimitiveSwaggerTypeToClrType(arrayType, null);
                        CodeTypeReference arrayCodeTypeReference = CreateArrayTypeReference(clrType, 1);
                        return(arrayCodeTypeReference);
                    }
                }
                else if (content.Schema.Enum.Count == 0)                 // for primitive type
                {
                    Type simpleType = PrimitiveSwaggerTypeToClrType(content.Schema.Type, content.Schema.Format);
                    CodeTypeReference codeTypeReference = new CodeTypeReference(simpleType);
                    return(codeTypeReference);
                }
                else if (content.Schema.Enum.Count > 0)
                {
                    var refinedTypeName = NameFunc.RefineTypeName(content.Schema.Type, content.Schema.Format);
                    schemaType = refinedTypeName;
                }

                string schemaFormat = content.Schema.Format;
                return(new CodeTypeReference(PrimitiveSwaggerTypeToClrType(schemaType, schemaFormat)));
            }

            return(null);
        }
Exemple #7
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));
        }
Exemple #8
0
        public void CreateCodeDom(OpenApiComponents components)
        {
            if (components == null)
            {
                return;
            }

            ComponentsSchemas = components.Schemas;            //.OrderBy(d => d.Value.Reference != null).OrderBy(k => k.Value.Properties.Count > 0).OrderBy(g => g.Value.AllOf.Count > 0).OrderBy(d => d.Value.Type != "array"); //so simple complex types will be handled first to be referenced by more complex ones.
            var classNamespaceNames = NameFunc.FindNamespacesInClassNames(ComponentsSchemas.Keys);

            if (classNamespaceNames.Length > 0)
            {
                var groupedComponentsSchemas = ComponentsSchemas
                                               .GroupBy(d => NameFunc.GetNamespaceOfClassName(d.Key))
                                               .OrderBy(k => k.Key);
                var namespacesOfTypes = groupedComponentsSchemas.Select(d => d.Key).ToArray();
                foreach (var groupedTypes in groupedComponentsSchemas)
                {
                    var classNamespaceText = groupedTypes.Key;
                    var classNamespace     = new CodeNamespace(classNamespaceText);
                    codeCompileUnit.Namespaces.Add(classNamespace);
                    ClassNamespaces.Add(classNamespace);
                    foreach (var kv in groupedTypes.OrderBy(t => t.Key))
                    {
                        var existingType = ComponentsHelper.FindTypeDeclarationInNamespace(NameFunc.RefineTypeName(kv.Key, classNamespaceText), classNamespace);
                        if (existingType == null)
                        {
                            AddTypeToCodeDom(kv);
                        }
                    }
                }
            }
            else
            {
                foreach (KeyValuePair <string, OpenApiSchema> item in ComponentsSchemas)
                {
                    var existingType = FindTypeDeclarationInNamespaces(NameFunc.RefineTypeName(item.Key, null), null);
                    if (existingType == null)
                    {
                        AddTypeToCodeDom(item);
                    }
                }
            }
        }
        /// <summary>
        /// Get CodeTypeReference and description of requestBody of operation.
        /// </summary>
        /// <param name="op"></param>
        /// <returns>bool is whether to support generating codes for this.</returns>
        public Tuple <CodeTypeReference, string, bool> GetBodyContent(OpenApiOperation op, string httpMethod, string path)
        {
            if (op.RequestBody != null && op.RequestBody.Content != null)
            {
                OpenApiMediaType content;
                string           description = op.RequestBody.Description;

                if (op.RequestBody.Reference != null)
                {
                    if (op.RequestBody.Content.TryGetValue("application/json", out content) && (content.Schema.Type != null && content.Schema.Type != "object"))
                    {
                        try
                        {
                            return(Tuple.Create(com2CodeDom.PropertySchemaToCodeTypeReference(content.Schema, actionName, httpMethod + "Body"), description, true));
                        }
                        catch (ArgumentException ex)
                        {
                            throw new CodeGenException($"Definition {path}=>{httpMethod} for op.RequestBody.Reference triggers error: {ex.Message}");
                        }
                    }

                    var               ns                = NameFunc.GetNamespaceOfClassName(op.RequestBody.Reference.Id);
                    string            typeName          = NameFunc.RefineTypeName(op.RequestBody.Reference.Id, ns);
                    CodeTypeReference codeTypeReference = new CodeTypeReference(NameFunc.CombineNamespaceWithClassName(ns, typeName));
                    return(Tuple.Create(codeTypeReference, description, true));
                }
                else if (op.RequestBody.Content.TryGetValue("application/json", out content))
                {
                    if (content.Schema != null)
                    {
                        return(Tuple.Create(com2CodeDom.PropertySchemaToCodeTypeReference(content.Schema, actionName, "Body"), description, true));
                    }
                }
                else if (op.RequestBody.Content.Count > 0)                 // with content but not supported
                {
                    return(Tuple.Create <CodeTypeReference, string, bool>(null, null, false));
                }
            }

            return(null);            //empty post
        }
Exemple #10
0
        /// <summary>
        /// Container class name for containing client functions, according OpenApiOperation and operation path.
        /// </summary>
        /// <param name="op"></param>
        /// <param name="path"></param>
        /// <returns></returns>
        public string GetContainerName(OpenApiOperation op, string path)
        {
            switch (settings.ContainerNameStrategy)
            {
            case ContainerNameStrategy.Path:
                return(NameFunc.ReplaceDashToTitleCase(PathToActionOrContainerName(path) + settings.ContainerNameSuffix));

            case ContainerNameStrategy.Tags:
                if (op.Tags != null && op.Tags.Count > 0)
                {
                    return(NameFunc.ReplaceDashToTitleCase(ToTitleCase(op.Tags[0].Name) + settings.ContainerNameSuffix));                           //todo: concanate multiple ones?
                }
                else
                {
                    return(settings.ContainerClassName);
                }

            default:
                return(settings.ContainerClassName);
            }
        }
        /// <summary>
        /// Generate action name hopefully unique across all paths and operations, under a god container class. Consisting of path, httpMethod and parameters.
        /// </summary>
        /// <param name="op"></param>
        /// <param name="httpMethod"></param>
        /// <param name="path"></param>
        /// <returns></returns>
        string ComposeActionNameWithPath(OpenApiOperation op, string httpMethod, string path)
        {
            string byWhat = String.Join("And", op.Parameters.Where(p => p.In == ParameterLocation.Query).Select(p => NameFunc.ToTitleCase(NameFunc.RefineParameterName(p.Name))));

            return(PathToActionOrContainerName(path) + httpMethod + (String.IsNullOrEmpty(byWhat) ? String.Empty : "By" + byWhat));
        }
Exemple #12
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="propertySchema"></param>
        /// <param name="currentTypeName"></param>
        /// <param name="propertyKey"></param>
        /// <returns>CodeTypeReference and IsClass</returns>
        protected Tuple <CodeTypeReference, bool> CreateCodeTypeReferenceSchemaOf(OpenApiSchema propertySchema, string currentTypeName, string propertyKey)
        {
            OpenApiSchema refToType = null;

            if (propertySchema.AllOf.Count > 0)
            {
                refToType = propertySchema.AllOf[0];
            }
            else if (propertySchema.OneOf.Count > 0)
            {
                refToType = propertySchema.OneOf[0];
            }
            else if (propertySchema.AnyOf.Count > 0)
            {
                refToType = propertySchema.AnyOf[0];
            }
            else if (refToType == null)
            {
                Trace.TraceWarning($"Property '{propertyKey}' of {currentTypeName} may be of type object.");
                return(Tuple.Create(new CodeTypeReference(typeof(object)), true));
            }

            CodeTypeReference ctr = PropertySchemaToCodeTypeReference(refToType, currentTypeName, NameFunc.RefinePropertyName(propertyKey));
            bool isClass          = !TypeRefHelper.IsPrimitiveStructure(ctr.BaseType);

            return(Tuple.Create(ctr, isClass));
        }
Exemple #13
0
        public override void AddEnumMembers(CodeTypeDeclaration typeDeclaration, IList <IOpenApiAny> enumTypeList)
        {
            int k = 0;

            foreach (IOpenApiAny enumMember in enumTypeList)
            {
                if (enumMember is OpenApiString stringMember)
                {
                    string          memberName         = NameFunc.RefineEnumMemberName(stringMember.Value);
                    bool            hasFunkyMemberName = memberName != stringMember.Value;
                    int             intValue           = k;
                    CodeMemberField clientField        = new CodeMemberField()
                    {
                        Name           = memberName,
                        InitExpression = new CodePrimitiveExpression(intValue),
                    };

                    typeDeclaration.Members.Add(clientField);
                    k++;
                }
                else if (enumMember is OpenApiInteger intMember)
                {
                    string          memberName  = "_" + intMember.Value.ToString();
                    int             intValue    = k;
                    CodeMemberField clientField = new CodeMemberField()
                    {
                        Name           = memberName,
                        InitExpression = new CodePrimitiveExpression(intValue),
                    };

                    typeDeclaration.Members.Add(clientField);
                    k++;
                }
                else if (enumMember is OpenApiLong longMember)
                {
                    string          memberName  = "_" + longMember.Value.ToString();
                    int             intValue    = k;
                    CodeMemberField clientField = new CodeMemberField()
                    {
                        Name           = memberName,
                        InitExpression = new CodePrimitiveExpression(intValue),
                    };

                    typeDeclaration.Members.Add(clientField);
                    k++;
                }
                else if (enumMember is OpenApiPassword passwordMember)                 // aws alexaforbusiness has PhoneNumberType defined as password format
                {
                    string          memberName  = NameFunc.RefineEnumMemberName(passwordMember.Value);
                    int             intValue    = k;
                    CodeMemberField clientField = new CodeMemberField()
                    {
                        Name           = memberName,
                        InitExpression = new CodePrimitiveExpression(intValue),
                    };

                    typeDeclaration.Members.Add(clientField);
                    k++;
                }
                else if (enumMember is OpenApiDouble doubleMember)                 //listennotes.com\2.0 has funky definition of casual enum of type double
                {
                    string          memberName  = "_" + doubleMember.Value.ToString();
                    int             intValue    = k;
                    CodeMemberField clientField = new CodeMemberField()
                    {
                        Name           = memberName,
                        InitExpression = new CodePrimitiveExpression(intValue),
                    };

                    typeDeclaration.Members.Add(clientField);
                    k++;
                }
                else
                {
                    throw new ArgumentException($"Not yet supported enumMember of {enumMember.GetType()} with {typeDeclaration.Name}");
                }
            }
        }
Exemple #14
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);
        }
Exemple #15
0
        protected override void AddProperty(KeyValuePair <string, OpenApiSchema> p, CodeTypeDeclaration typeDeclaration, OpenApiSchema schema, string currentTypeName, string ns)
        {
            string propertyName = NameFunc.RefineTsPropertyName(p.Key);

            if (propertyName == currentTypeName)
            {
                Trace.TraceWarning($"Property {propertyName} found with the same name of type {currentTypeName}, and it is renamed to {propertyName}1.");
                propertyName += "1";
            }

            if (!Char.IsLetter(propertyName[0]) && propertyName[0] != '_')
            {
                propertyName = "_" + propertyName;
            }

            OpenApiSchema   propertySchema        = p.Value;
            string          primitivePropertyType = propertySchema.Type;
            bool            isPrimitiveType       = TypeRefHelper.IsPrimitiveTypeOfOA(primitivePropertyType);
            bool            isRequired            = schema.Required.Contains(p.Key); //compare with the original key
            CodeMemberField clientProperty;

            if (String.IsNullOrEmpty(primitivePropertyType))
            {
                if (propertySchema.Reference != null)
                {
                    string            propertyTypeNs     = NameFunc.GetNamespaceOfClassName(propertySchema.Reference.Id);
                    string            propertyTypeName   = NameFunc.RefineTypeName(propertySchema.Reference.Id, propertyTypeNs);
                    string            propertyTypeWithNs = NameFunc.CombineNamespaceWithClassName(propertyTypeNs, propertyTypeName);
                    CodeTypeReference ctr = ComponentsHelper.TranslateTypeNameToClientTypeReference(propertyTypeWithNs);
                    clientProperty = CreateProperty(ctr, propertyName, isRequired);                     //TS
                }
                else
                {
                    if (propertySchema.Enum.Count > 0)                     //for casual enum
                    {
                        clientProperty = GenerateCasualEnumForProperty(propertySchema, typeDeclaration.Name, propertyName, ns, isRequired);
                    }
                    else
                    {
                        var r = CreateCodeTypeReferenceSchemaOf(propertySchema, currentTypeName, p.Key);
                        clientProperty = CreateProperty(r.Item1, propertyName, isRequired);
                    }
                }
            }
            else
            {
                if (propertySchema.Type == "array")                 // for array
                {
                    var r = CreateArrayCodeTypeReference(propertySchema, typeDeclaration.Name, propertyName, currentTypeName, ns);
                    CodeTypeReference arrayCodeTypeReference = r.Item1;
                    var n = String.IsNullOrEmpty(r.Item2) ? propertyName : r.Item2;
                    clientProperty = CreateProperty(arrayCodeTypeReference, n, isRequired);
                }
                else if (propertySchema.Enum.Count == 0 && propertySchema.Reference != null && !isPrimitiveType)                 // for complex type
                {
                    CodeTypeReference complexCodeTypeReference = CreateComplexCodeTypeReference(propertySchema);
                    clientProperty = CreateProperty(complexCodeTypeReference, propertyName, isRequired);
                }
                else if (propertySchema.Reference == null && propertySchema.Properties != null && propertySchema.Properties.Count > 0)                 // for casual type
                {
                    string casualTypeName = currentTypeName + NameFunc.RefinePropertyName(propertyName);
                    CodeTypeDeclaration casualTypeDeclaration = AddTypeToClassNamespace(casualTypeName, null);                    //stay with the namespace of the host class
                    AddProperties(casualTypeDeclaration, propertySchema, casualTypeName, null);
                    var ctr = TypeRefHelper.TranslateToClientTypeReference(casualTypeName);
                    clientProperty = CreateProperty(ctr, propertyName, isRequired);
                }
                else if (propertySchema.Type == "object" && propertySchema.AdditionalProperties != null)                 // for dictionary
                {
                    CodeTypeReference dicKeyTypeRef = TypeRefHelper.TranslateToClientTypeReference(typeof(string));
                    CodeTypeReference dicValueTypeRef;
                    if (propertySchema.AdditionalProperties.Properties.Count == 0 &&                  //not casual type
                        propertySchema.AdditionalProperties.Reference == null &&                         // not complex type
                        propertySchema.AdditionalProperties.Items == null)                            // not casual array type
                    {
                        dicValueTypeRef = new CodeTypeReference(typeof(object));
                    }
                    else
                    {
                        dicValueTypeRef = PropertySchemaToCodeTypeReference(propertySchema.AdditionalProperties, typeDeclaration.Name, propertyName);
                    }

                    CodeTypeReference dicCtr = new CodeTypeReference(typeof(Dictionary <,>).FullName, dicKeyTypeRef, dicValueTypeRef);                    //for client codes, Dictionary is better than IDictionary, no worry of different implementation of IDictionary
                    clientProperty = CreateProperty(dicCtr, propertyName, isRequired);
                }
                else if (propertySchema.Enum.Count == 0)                 // for primitive type
                {
                    Type simpleType = TypeRefHelper.PrimitiveSwaggerTypeToClrType(primitivePropertyType, propertySchema.Format);
                    clientProperty = CreatePropertyOfType(propertyName, simpleType, isRequired);
                }
                else if (propertySchema.Enum.Count > 0 && propertySchema.Type == "string")                 // for enum
                {
                    string[] enumMemberNames;
                    try
                    {
                        enumMemberNames = (String.IsNullOrEmpty(propertySchema.Type) || propertySchema.Type == "string")
                                                        ? propertySchema.Enum.Cast <OpenApiString>().Select(m => m.Value).ToArray()
                                                        : propertySchema.Enum.Cast <OpenApiInteger>().Select(m => "_" + m.Value.ToString()).ToArray();
                    }
                    catch (InvalidCastException ex)
                    {
                        throw new CodeGenException($"When dealing with {propertyName} of {propertySchema.Type}, error: {ex.Message}");
                    }

                    CodeTypeDeclaration existingDeclaration = FindEnumDeclaration(enumMemberNames);
                    if (existingDeclaration != null)
                    {
                        string            existingTypeName = existingDeclaration.Name;
                        CodeTypeReference enumReference    = TypeRefHelper.TranslateToClientTypeReference(existingTypeName);
                        clientProperty = CreateProperty(enumReference, propertyName, isRequired);
                    }
                    else
                    {
                        clientProperty = GenerateCasualEnumForProperty(propertySchema, typeDeclaration.Name, propertyName, ns, isRequired);
                    }
                }
                else if (propertySchema.Type != "string" && TypeAliasDic.TryGet(propertySchema.Type, out string aliasTypeName))                 //check TypeAliasDic
                {
                    var r = new CodeTypeReference(aliasTypeName);
                    clientProperty = CreateProperty(r, propertyName, isRequired);
                }
                else if (propertySchema.Reference != null)
                {
                    CodeTypeReference complexCodeTypeReference = CreateComplexCodeTypeReference(propertySchema);
                    clientProperty = CreateProperty(complexCodeTypeReference, propertyName, isRequired);
                }
                else                 // for casual enum
                {
                    clientProperty = GenerateCasualEnumForProperty(propertySchema, typeDeclaration.Name, propertyName, ns, isRequired);
                }
            }

            CreateMemberDocComment(p, clientProperty);
            typeDeclaration.Members.Add(clientProperty);
        }
        /// <summary>
        /// Compose action name according to tags, httpMethod and Parameters.
        /// </summary>
        /// <param name="op"></param>
        /// <param name="httpMethod"></param>
        /// <returns></returns>
        public static string ComposeActionName(OpenApiOperation op, string httpMethod)
        {
            if (op.Tags == null || op.Tags.Count == 0)
            {
                throw new ArgumentException("OpenApiOperation does not contain tags for composing action name.");
            }

            string byWhat = String.Join("And", op.Parameters.Where(p => p.In == ParameterLocation.Path || p.In == ParameterLocation.Query).Select(p => NameFunc.ToTitleCase(NameFunc.RefineParameterName(p.Name))));

            return(ToTitleCase(op.Tags[0].Name) + httpMethod + (String.IsNullOrEmpty(byWhat) ? String.Empty : "By" + byWhat));
        }
        public override void AddEnumMembers(CodeTypeDeclaration typeDeclaration, IList <IOpenApiAny> enumTypeList)
        {
            int k = 0;

            foreach (IOpenApiAny enumMember in enumTypeList)
            {
                if (enumMember is OpenApiString stringMember)
                {
                    string          memberName         = NameFunc.RefineEnumMemberName(stringMember.Value, settings);
                    bool            hasFunkyMemberName = memberName != stringMember.Value;
                    int             intValue           = k;
                    CodeMemberField clientField        = new CodeMemberField()
                    {
                        Name           = memberName,
                        InitExpression = new CodePrimitiveExpression(intValue),
                    };

                    if (settings.DecorateDataModelWithDataContract)
                    {
                        if (hasFunkyMemberName || settings.EnumToString)
                        {
                            clientField.CustomAttributes.Add(new CodeAttributeDeclaration($"System.Runtime.Serialization.EnumMemberAttribute", new CodeAttributeArgument("Value", new CodeSnippetExpression($"\"{stringMember.Value}\""))));
                        }
                        else
                        {
                            clientField.CustomAttributes.Add(new CodeAttributeDeclaration("System.Runtime.Serialization.EnumMemberAttribute"));
                        }
                    }

                    typeDeclaration.Members.Add(clientField);
                    k++;
                }
                else if (enumMember is OpenApiInteger intMember)
                {
                    string          memberName  = NameFunc.RefineEnumMemberName(intMember.Value.ToString());          //take care of negative value
                    int             intValue    = intMember.Value;
                    CodeMemberField clientField = new CodeMemberField()
                    {
                        Name           = memberName,
                        InitExpression = new CodePrimitiveExpression(intValue),
                    };

                    if (settings.DecorateDataModelWithDataContract)
                    {
                        clientField.CustomAttributes.Add(new CodeAttributeDeclaration("System.Runtime.Serialization.EnumMemberAttribute"));
                    }

                    typeDeclaration.Members.Add(clientField);
                    k++;
                }
                else if (enumMember is OpenApiLong longMember)
                {
                    string          memberName  = NameFunc.RefineEnumMemberName(longMember.Value.ToString());
                    long            longValue   = longMember.Value;
                    CodeMemberField clientField = new CodeMemberField()
                    {
                        Name           = memberName,
                        InitExpression = new CodePrimitiveExpression(longValue),
                    };

                    if (settings.DecorateDataModelWithDataContract)
                    {
                        clientField.CustomAttributes.Add(new CodeAttributeDeclaration("System.Runtime.Serialization.EnumMemberAttribute"));
                    }

                    typeDeclaration.Members.Add(clientField);
                    k++;
                }
                else if (enumMember is OpenApiPassword passwordMember)                 // aws alexaforbusiness has PhoneNumberType defined as password format
                {
                    string          memberName  = NameFunc.RefineEnumMemberName(passwordMember.Value);
                    int             intValue    = k;
                    CodeMemberField clientField = new CodeMemberField()
                    {
                        Name           = memberName,
                        InitExpression = new CodePrimitiveExpression(intValue),
                    };

                    if (settings.DecorateDataModelWithDataContract)
                    {
                        clientField.CustomAttributes.Add(new CodeAttributeDeclaration("System.Runtime.Serialization.EnumMemberAttribute"));
                    }

                    typeDeclaration.Members.Add(clientField);
                    k++;
                }
                else if (enumMember is OpenApiDouble doubleMember)                 //listennotes.com\2.0 has funky definition of casual enum of type double
                {
                    string          memberName  = "_" + doubleMember.Value.ToString();
                    double          doubleValue = doubleMember.Value;
                    CodeMemberField clientField = new CodeMemberField()
                    {
                        Name           = memberName,
                        InitExpression = new CodePrimitiveExpression(doubleValue),
                    };

                    if (settings.DecorateDataModelWithDataContract)
                    {
                        clientField.CustomAttributes.Add(new CodeAttributeDeclaration("System.Runtime.Serialization.EnumMemberAttribute"));
                    }

                    typeDeclaration.Members.Add(clientField);
                    k++;
                }
                else
                {
                    throw new ArgumentException($"Not yet supported enumMember of {enumMember.GetType()} with {typeDeclaration.Name}");
                }
            }
        }
Exemple #18
0
        /// <summary>
        /// Mostly used in ParametersRefBuilder.
        /// </summary>
        /// <param name="propertySchema"></param>
        /// <param name="actionName"></param>
        /// <param name="propertyName"></param>
        /// <returns></returns>
        /// <remarks>This shares similar navigation of schema like those in AddProperty().</remarks>
        public CodeTypeReference PropertySchemaToCodeTypeReference(OpenApiSchema propertySchema, string actionName, string propertyName)
        {
            string schemaType      = propertySchema.Type;
            bool   isPrimitiveType = TypeRefHelper.IsPrimitiveTypeOfOA(schemaType);

            if (String.IsNullOrEmpty(schemaType))
            {
                if (propertySchema.Reference != null)
                {
                    string propertyTypeNs     = NameFunc.GetNamespaceOfClassName(propertySchema.Reference.Id);
                    string propertyTypeName   = NameFunc.RefineTypeName(propertySchema.Reference.Id, propertyTypeNs);
                    string propertyTypeWithNs = NameFunc.CombineNamespaceWithClassName(propertyTypeNs, propertyTypeName);
                    return(ComponentsHelper.TranslateTypeNameToClientTypeReference(propertyTypeWithNs));
                }
                else
                {
                    if (propertySchema.Enum.Count > 0)                     //for casual enum
                    {
                        var r = GenerateCasualEnum(propertySchema, actionName, propertyName, null);
                        return(r.Item1);
                    }
                    else
                    {
                        Tuple <CodeTypeReference, bool> r = CreateCodeTypeReferenceSchemaOf(propertySchema, actionName, propertyName);
                        return(r.Item1);
                    }
                }
            }
            else
            {
                if (schemaType == "array")                 // for array
                {
                    var r = CreateArrayCodeTypeReference(propertySchema, actionName, propertyName, null, null);
                    return(r.Item1);
                }
                else if (propertySchema.Enum.Count == 0 && propertySchema.Reference != null && !isPrimitiveType)                 // for complex type
                {
                    CodeTypeReference complexCodeTypeReference = CreateComplexCodeTypeReference(propertySchema);
                    return(complexCodeTypeReference);
                }
                else if (propertySchema.Reference == null && propertySchema.Properties != null && propertySchema.Properties.Count > 0)                 // for casual type
                {
                    string casualTypeName = actionName + NameFunc.RefinePropertyName(propertyName);
                    var    found          = FindTypeDeclarationInNamespaces(casualTypeName, null);         //It could happenen when generating sync and async functions in C#
                    if (found == null)
                    {
                        CodeTypeDeclaration casualTypeDeclaration = AddTypeToClassNamespace(casualTypeName, null);                        //stay with the namespace of the host class
                        AddProperties(casualTypeDeclaration, propertySchema, casualTypeName, null);
                    }

                    return(TypeRefHelper.TranslateToClientTypeReference(casualTypeName));
                }
                else if (schemaType == "object" && propertySchema.AdditionalProperties != null)                 // for dictionary
                {
                    CodeTypeReference dicKeyTypeRef   = TypeRefHelper.TranslateToClientTypeReference(typeof(string));
                    CodeTypeReference dicValueTypeRef = PropertySchemaToCodeTypeReference(propertySchema.AdditionalProperties, actionName, propertyName);
                    return(new CodeTypeReference(typeof(Dictionary <,>).FullName, dicKeyTypeRef, dicValueTypeRef)); //for client codes, Dictionary is better than IDictionary, no worry of different implementation of IDictionary
                }
                else if (propertySchema.Enum.Count == 0)                                                            // for primitive type
                {
                    Type t = TypeRefHelper.PrimitiveSwaggerTypeToClrType(schemaType, propertySchema.Format);
                    return(new CodeTypeReference(t));
                }
                else if (propertySchema.Enum.Count > 0 && schemaType == "string")                 // for enum
                {
                    string[] enumMemberNames;
                    try
                    {
                        enumMemberNames = (String.IsNullOrEmpty(propertySchema.Type) || propertySchema.Type == "string")
                                                        ? propertySchema.Enum.Cast <OpenApiString>().Select(m => m.Value).ToArray()
                                                        : propertySchema.Enum.Cast <OpenApiInteger>().Select(m => "_" + m.Value.ToString()).ToArray();
                    }
                    catch (InvalidCastException ex)
                    {
                        throw new CodeGenException($"When dealing with {propertyName} of {schemaType}, error: {ex.Message}");
                    }

                    CodeTypeDeclaration existingDeclaration = FindEnumDeclaration(enumMemberNames);
                    if (existingDeclaration != null)
                    {
                        string            existingTypeName = existingDeclaration.Name;
                        CodeTypeReference enumReference    = TypeRefHelper.TranslateToClientTypeReference(existingTypeName);
                        return(enumReference);
                    }
                    else
                    {
                        var r = GenerateCasualEnum(propertySchema, actionName, propertyName, null);
                        return(r.Item1);
                    }
                }
                else if (schemaType != "string" && TypeAliasDic.TryGet(schemaType, out string aliasTypeName))                 //check TypeAliasDic
                {
                    return(new CodeTypeReference(aliasTypeName));
                }
                else if (propertySchema.Reference != null)
                {
                    CodeTypeReference complexCodeTypeReference = CreateComplexCodeTypeReference(propertySchema);
                    return(complexCodeTypeReference);
                }
                else                 // for casual enum
                {
                    var r = GenerateCasualEnum(propertySchema, actionName, propertyName, null);
                    return(r.Item1);
                }
            }
        }
        protected override void AddProperty(KeyValuePair <string, OpenApiSchema> p, CodeTypeDeclaration typeDeclaration, OpenApiSchema schema, string currentTypeName, string ns)
        {
            string propertyName = NameFunc.RefinePropertyName(p.Key);

            if (propertyName == currentTypeName)
            {
                Trace.TraceWarning($"Property {propertyName} found with the same name of type {currentTypeName}, and it is renamed to {propertyName}1.");
                propertyName += "1";
            }

            if (!Char.IsLetter(propertyName[0]) && propertyName[0] != '_')
            {
                propertyName = "_" + propertyName;
            }

            bool propertyNameAdjusted = propertyName != p.Key;

            OpenApiSchema   propertySchema        = p.Value;
            string          primitivePropertyType = propertySchema.Type;
            bool            isPrimitiveType       = TypeRefHelper.IsPrimitiveTypeOfOA(primitivePropertyType);
            bool            isRequired            = schema.Required.Contains(p.Key); //compare with the original key
            string          defaultValue          = GetDefaultValue(propertySchema);
            CodeMemberField clientProperty;

            if (String.IsNullOrEmpty(primitivePropertyType))
            {
                if (propertySchema.Reference != null)
                {
                    string            propertyTypeNs     = NameFunc.GetNamespaceOfClassName(propertySchema.Reference.Id);
                    string            propertyTypeName   = NameFunc.RefineTypeName(propertySchema.Reference.Id, propertyTypeNs);
                    string            propertyTypeWithNs = NameFunc.CombineNamespaceWithClassName(propertyTypeNs, propertyTypeName);
                    CodeTypeReference ctr = ComponentsHelper.TranslateTypeNameToClientTypeReference(propertyTypeWithNs);
                    clientProperty = CreateProperty(ctr, propertyName, defaultValue);                     //C#
                }
                else
                {
                    if (propertySchema.Enum.Count > 0)                     //for casual enum
                    {
                        clientProperty = GenerateCasualEnumForProperty(propertySchema, typeDeclaration.Name, propertyName, ns, defaultValue, !isRequired || propertySchema.Nullable);
                    }
                    else
                    {
                        Tuple <CodeTypeReference, bool> r = CreateCodeTypeReferenceSchemaOf(propertySchema, currentTypeName, p.Key);
                        bool isClass = r.Item2;
                        if ((!settings.DisableSystemNullableByDefault && !isRequired || propertySchema.Nullable) && !isClass)                         //C#.
                        //if (!settings.DisableSystemNullableByDefault && !isClass && !isRequired || propertySchema.Nullable) //C#
                        {
                            clientProperty = CreateNullableProperty(r.Item1, propertyName);
                        }
                        else if (isClass && propertySchema.Nullable && settings.UseNullableReferenceType)                         //vimeo yaml declares a reference type as nullable.
                        {
                            clientProperty = CreateNullableProperty(r.Item1, propertyName);
                        }
                        else
                        {
                            clientProperty = CreateProperty(r.Item1, propertyName, defaultValue);
                        }
                    }
                }
            }
            else
            {
                if (propertySchema.Type == "array")                 // for array
                {
                    Tuple <CodeTypeReference, string> r      = CreateArrayCodeTypeReference(propertySchema, typeDeclaration.Name, propertyName, currentTypeName, ns);
                    CodeTypeReference arrayCodeTypeReference = r.Item1;
                    string            n = String.IsNullOrEmpty(r.Item2) ? propertyName : r.Item2;
                    clientProperty = CreateProperty(arrayCodeTypeReference, n, defaultValue);
                }
                else if (propertySchema.Enum.Count == 0 && propertySchema.Reference != null && !isPrimitiveType)                 // for complex type
                {
                    CodeTypeReference complexCodeTypeReference = CreateComplexCodeTypeReference(propertySchema);
                    clientProperty = CreateProperty(complexCodeTypeReference, propertyName, defaultValue);
                }
                else if (propertySchema.Reference == null && propertySchema.Properties != null && propertySchema.Properties.Count > 0)                 // for casual type
                {
                    string casualTypeName     = currentTypeName + NameFunc.RefinePropertyName(propertyName);
                    CodeTypeDeclaration found = FindTypeDeclarationInNamespaces(casualTypeName, null);                     //It could happenen when generating sync and async functions in C#
                    if (found == null)
                    {
                        CodeTypeDeclaration casualTypeDeclaration = AddTypeToClassNamespace(casualTypeName, null);                        //stay with the namespace of the host class
                        AddProperties(casualTypeDeclaration, propertySchema, casualTypeName, null);
                    }

                    CodeTypeReference ctr = TypeRefHelper.TranslateToClientTypeReference(casualTypeName);
                    clientProperty = CreateProperty(ctr, propertyName, defaultValue);
                }
                else if (propertySchema.Type == "object" && propertySchema.AdditionalProperties != null)                 // for dictionary
                {
                    CodeTypeReference dicKeyTypeRef = TypeRefHelper.TranslateToClientTypeReference(typeof(string));
                    CodeTypeReference dicValueTypeRef;
                    if (propertySchema.AdditionalProperties.Properties.Count == 0 &&                  //not casual type
                        propertySchema.AdditionalProperties.Reference == null &&                         // not complex type
                        propertySchema.AdditionalProperties.Items == null)                            // not casual array type
                    {
                        dicValueTypeRef = new CodeTypeReference(typeof(object));
                    }
                    else
                    {
                        dicValueTypeRef = PropertySchemaToCodeTypeReference(propertySchema.AdditionalProperties, typeDeclaration.Name, propertyName);
                    }

                    CodeTypeReference dicCtr = new CodeTypeReference(typeof(Dictionary <,>).FullName, dicKeyTypeRef, dicValueTypeRef);                    //for client codes, Dictionary is better than IDictionary, no worry of different implementation of IDictionary
                    clientProperty = CreateProperty(dicCtr, propertyName, null);
                }
                else if (propertySchema.Enum.Count == 0)                 // for primitive type
                {
                    Type simpleType = TypeRefHelper.PrimitiveSwaggerTypeToClrType(primitivePropertyType, propertySchema.Format);
                    if ((!settings.DisableSystemNullableByDefault && !isRequired || propertySchema.Nullable) && !simpleType.IsClass)                     //C#
                    {
                        clientProperty = CreateNullableProperty(propertyName, simpleType, settings, propertySchema.Nullable);
                    }
                    else if (propertySchema.Nullable && simpleType.IsClass && settings.UseNullableReferenceType)
                    {
                        clientProperty = CreateNullableProperty(propertyName, simpleType, settings, propertySchema.Nullable);
                    }
                    else
                    {
                        clientProperty = CreateProperty(propertyName, simpleType, defaultValue);
                    }
                }
                else if (propertySchema.Enum.Count > 0 && propertySchema.Type == "string")                 // for enum
                {
                    string[] enumMemberNames;
                    try
                    {
                        enumMemberNames = (String.IsNullOrEmpty(propertySchema.Type) || propertySchema.Type == "string")
                                                        ? propertySchema.Enum.Cast <OpenApiString>().Select(m => m.Value).ToArray()
                                                        : propertySchema.Enum.Cast <OpenApiInteger>().Select(m => "_" + m.Value.ToString()).ToArray();
                    }
                    catch (InvalidCastException ex)
                    {
                        throw new CodeGenException($"When dealing with {propertyName} of {propertySchema.Type}, error: {ex.Message}");
                    }

                    CodeTypeDeclaration existingDeclaration = FindEnumDeclaration(enumMemberNames);
                    if (existingDeclaration != null)
                    {
                        string            existingTypeName = existingDeclaration.Name;
                        CodeTypeReference enumReference    = TypeRefHelper.TranslateToClientTypeReference(existingTypeName);
                        clientProperty = CreateProperty(enumReference, propertyName, String.IsNullOrEmpty(defaultValue) ? null : enumReference.BaseType + "." + defaultValue);
                    }
                    else
                    {
                        clientProperty = GenerateCasualEnumForProperty(propertySchema, typeDeclaration.Name, propertyName, ns, defaultValue, !isRequired || propertySchema.Nullable);
                    }
                }
                else if (propertySchema.Type != "string" && TypeAliasDic.TryGet(propertySchema.Type, out string aliasTypeName))                 //check TypeAliasDic
                {
                    CodeTypeReference r = new CodeTypeReference(aliasTypeName);
                    clientProperty = CreateProperty(r, propertyName, defaultValue);
                }
                else if (propertySchema.Reference != null)
                {
                    CodeTypeReference complexCodeTypeReference = CreateComplexCodeTypeReference(propertySchema);
                    clientProperty = CreateProperty(complexCodeTypeReference, propertyName, String.IsNullOrEmpty(defaultValue) ? null : complexCodeTypeReference.BaseType + "." + defaultValue);
                }
                else                 // for casual enum
                {
                    clientProperty = GenerateCasualEnumForProperty(propertySchema, typeDeclaration.Name, propertyName, ns, defaultValue, !isRequired || propertySchema.Nullable);
                }
            }

            if (isRequired)
            {
                clientProperty.CustomAttributes.Add(new CodeAttributeDeclaration("System.ComponentModel.DataAnnotations.Required"));
            }

            if (settings.DecorateDataModelWithDataContract)
            {
                if (propertyNameAdjusted)
                {
                    string originalPropertyName = p.Key;
                    clientProperty.CustomAttributes.Add(new CodeAttributeDeclaration("System.Runtime.Serialization.DataMember", new CodeAttributeArgument("Name", new CodeSnippetExpression($"\"{originalPropertyName}\""))));
                }
                else
                {
                    clientProperty.CustomAttributes.Add(new CodeAttributeDeclaration("System.Runtime.Serialization.DataMember"));
                }
            }

            if (settings.DataAnnotationsEnabled)             //C#
            {
                AddValidationAttributes(propertySchema, clientProperty);
            }

            if (settings.DecorateDataModelWithPropertyName)             //C#
            {
                string originalPropertyName = p.Key;
                if (settings.UseSystemTextJson)
                {
                    //[System.Text.Json.Serialization.JsonPropertyName("name")]
                    clientProperty.CustomAttributes.Add(new CodeAttributeDeclaration("System.Text.Json.Serialization.JsonPropertyName", new CodeAttributeArgument(new CodeSnippetExpression($"\"{originalPropertyName}\""))));
                }
                else
                {
                    //[Newtonsoft.Json.JsonProperty(PropertyName = "name")]
                    clientProperty.CustomAttributes.Add(new CodeAttributeDeclaration("Newtonsoft.Json.JsonProperty", new CodeAttributeArgument("PropertyName", new CodeSnippetExpression($"\"{originalPropertyName}\""))));
                }
            }

            CreateMemberDocComment(p, clientProperty);
            typeDeclaration.Members.Add(clientProperty);
        }
Exemple #20
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="propertySchema"></param>
        /// <param name="typeDeclarationName"></param>
        /// <param name="propertyName"></param>
        /// <param name="currentTypeName"></param>
        /// <param name="ns"></param>
        /// <returns>CodeTypeReference and CasualTypeName. Empty if no casualTypeName.</returns>
        public Tuple <CodeTypeReference, string> CreateArrayCodeTypeReference(OpenApiSchema propertySchema, string typeDeclarationName, string propertyName, string currentTypeName, string ns)
        {
            OpenApiSchema arrayItemsSchema = propertySchema.Items;

            if (arrayItemsSchema == null)            //ritekit.com has parameter as array but without items type. Presumbly it may be string.
            {
                Type clrType = TypeRefHelper.PrimitiveSwaggerTypeToClrType("string", null);
                CodeTypeReference arrayCodeTypeReference = TypeRefHelper.CreateArrayTypeReference(clrType, 1);
                return(Tuple.Create(arrayCodeTypeReference, String.Empty));
            }
            else if (arrayItemsSchema.Reference != null)             //array of custom type
            {
                string arrayTypeSchemaRefId = arrayItemsSchema.Reference.Id;
                var    arrayTypeNs          = NameFunc.GetNamespaceOfClassName(arrayTypeSchemaRefId);
                var    arrayTypeName        = NameFunc.RefineTypeName(arrayTypeSchemaRefId, arrayTypeNs);
                var    arrayTypeWithNs      = NameFunc.CombineNamespaceWithClassName(arrayTypeNs, arrayTypeName);
                var    existingType         = FindTypeDeclarationInNamespaces(arrayTypeName, arrayTypeNs);
                if (existingType == null)                 // Referencing to a type not yet added to namespace
                {
                    var existingSchema = FindSchema(arrayTypeSchemaRefId);
                    if (existingSchema != null && !RegisteredSchemaRefIdExists(arrayTypeSchemaRefId))
                    {
                        AddTypeToCodeDom(new KeyValuePair <string, OpenApiSchema>(arrayTypeSchemaRefId, existingSchema));
                    }
                }

                if (TypeAliasDic.TryGet(arrayTypeSchemaRefId, out string arrayTypeNameAlias))
                {
                    if (!TypeRefHelper.IsSwaggerPrimitive(arrayTypeNameAlias))
                    {
                        return(Tuple.Create(ComponentsHelper.CreateArrayOfCustomTypeReference(arrayTypeNameAlias, 1), String.Empty));
                    }
                    else
                    {
                        var clrType = TypeRefHelper.PrimitiveSwaggerTypeToClrType(arrayTypeNameAlias, null);
                        return(Tuple.Create(ComponentsHelper.CreateArrayOfCustomTypeReference(clrType.FullName, 1), String.Empty));
                    }
                }
                else
                {
                    return(Tuple.Create(ComponentsHelper.CreateArrayOfCustomTypeReference(arrayTypeWithNs, 1), String.Empty));
                }
            }
            else
            {
                string arrayType = arrayItemsSchema.Type;
                if (arrayItemsSchema.Enum != null && arrayItemsSchema.Enum.Count > 0)
                {
                    string[] enumMemberNames;
                    try
                    {
                        enumMemberNames = (String.IsNullOrEmpty(arrayItemsSchema.Type) || arrayItemsSchema.Type == "string")
                                                        ? arrayItemsSchema.Enum.Cast <OpenApiString>().Select(m => m.Value).ToArray()
                                                        : arrayItemsSchema.Enum.Cast <OpenApiInteger>().Select(m => "_" + m.Value.ToString()).ToArray();
                    }
                    catch (InvalidCastException ex)
                    {
                        throw new CodeGenException($"When dealing with {propertyName} of {arrayType}, error: {ex.Message}");
                    }

                    CodeTypeDeclaration existingDeclaration = FindEnumDeclaration(enumMemberNames);
                    if (existingDeclaration != null)
                    {
                        string            existingTypeName   = existingDeclaration.Name;
                        CodeTypeReference enumArrayReference = TypeRefHelper.CreateArrayOfCustomTypeReference(existingTypeName, 1);
                        return(Tuple.Create(enumArrayReference, String.Empty));
                    }

                    //warning about bad yaml design.
                    Trace.TraceWarning($"Property {NameFunc.RefineParameterName(propertyName)} has referenced some enum members {String.Join(", ", enumMemberNames)} which are not of any declared components.");
                }
                else if (arrayItemsSchema.Properties != null && arrayItemsSchema.Properties.Count > 0)                 // for casual type
                {
                    string casualTypeName = typeDeclarationName + NameFunc.RefinePropertyName(propertyName);
                    CodeTypeDeclaration casualTypeDeclaration = AddTypeToClassNamespace(casualTypeName, ns);                    //stay with the namespace of the host class
                    AddProperties(casualTypeDeclaration, arrayItemsSchema, currentTypeName, ns);
                    return(Tuple.Create(ComponentsHelper.CreateArrayOfCustomTypeReference(casualTypeName, 1), casualTypeName));
                }

                Type clrType = TypeRefHelper.PrimitiveSwaggerTypeToClrType(arrayType, null);
                return(Tuple.Create(TypeRefHelper.CreateArrayTypeReference(clrType, 1), String.Empty));
            }
        }
        /// <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);
        }