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()); }
/// <summary> /// /// </summary> /// <param name="op"></param> /// <returns>item2 indicates whether return is a string.</returns> public Tuple <CodeTypeReference, bool> GetOperationReturnTypeReference(OpenApiOperation op) { if (op.Responses.TryGetValue("200", out OpenApiResponse goodResponse)) { CodeTypeReference codeTypeReference; if (goodResponse.Content.TryGetValue("application/json", out OpenApiMediaType content)) // application/json has better to be first. { if (content == null || content.Schema == null) { return(Tuple.Create <CodeTypeReference, bool>(null, false)); } try { codeTypeReference = com2CodeDom.PropertySchemaToCodeTypeReference(content.Schema, actionName, "Return"); } catch (ArgumentException ex) { throw new CodeGenException(ex.Message) { Pending = true }; } return(Tuple.Create(codeTypeReference, false)); } if (goodResponse.Content.TryGetValue("text/plain", out content)) { if (content.Schema != null) { string schemaType = content.Schema.Type; if (schemaType != null) { string schemaFormat = content.Schema.Format; Type type = TypeRefHelper.PrimitiveSwaggerTypeToClrType(schemaType, schemaFormat); return(Tuple.Create(new CodeTypeReference(type), type == typeOfString)); } } } } return(Tuple.Create <CodeTypeReference, bool>(null, false)); }
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); }
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> /// 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); } } }
/// <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); }
static void AddValidationAttributes(OpenApiSchema fieldSchema, CodeMemberField memberField) { if (fieldSchema.MaxLength.HasValue || fieldSchema.MinLength.HasValue) { if (fieldSchema.Type == "string") { List <CodeAttributeArgument> attributeParams = new List <CodeAttributeArgument>(); if (fieldSchema.MaxLength.HasValue) { CodeSnippetExpression max = new CodeSnippetExpression(fieldSchema.MaxLength.Value.ToString()); attributeParams.Add(new CodeAttributeArgument(max)); } else { CodeSnippetExpression max = new CodeSnippetExpression("int.MaxValue"); attributeParams.Add(new CodeAttributeArgument(max)); } if (fieldSchema.MinLength.HasValue) { CodeSnippetExpression min = new CodeSnippetExpression(fieldSchema.MinLength.Value.ToString()); attributeParams.Add(new CodeAttributeArgument("MinimumLength", min)); } CodeAttributeDeclaration cad = new CodeAttributeDeclaration("System.ComponentModel.DataAnnotations.StringLength", attributeParams.ToArray()); memberField.CustomAttributes.Add(cad); } else { if (fieldSchema.MinLength.HasValue) { CodeSnippetExpression len = new CodeSnippetExpression(fieldSchema.MinLength.Value.ToString()); CodeAttributeArgument[] attributeParams = new CodeAttributeArgument[] { new CodeAttributeArgument(len) }; CodeAttributeDeclaration cad = new CodeAttributeDeclaration("System.ComponentModel.DataAnnotations.MinLength", attributeParams); memberField.CustomAttributes.Add(cad); } if (fieldSchema.MaxLength.HasValue) { CodeSnippetExpression len = new CodeSnippetExpression(fieldSchema.MaxLength.Value.ToString()); CodeAttributeArgument[] attributeParams = new CodeAttributeArgument[] { new CodeAttributeArgument(len) }; CodeAttributeDeclaration cad = new CodeAttributeDeclaration("System.ComponentModel.DataAnnotations.MaxLength", attributeParams); memberField.CustomAttributes.Add(cad); } } } if (fieldSchema.Maximum.HasValue || fieldSchema.Minimum.HasValue) { Type type = TypeRefHelper.PrimitiveSwaggerTypeToClrType(fieldSchema.Type, fieldSchema.Format); List <CodeAttributeArgument> attributeParams = new List <CodeAttributeArgument>(); if (fieldSchema.Type == "string") { Trace.TraceWarning("A string type property shouldn't be decorated by Maximum or Minimum but MaxLength or MinLength."); //Xero_bankfeeds.yaml has such problem. return; } if (fieldSchema.Minimum.HasValue) { CodeSnippetExpression min = new CodeSnippetExpression($"{fieldSchema.Minimum.Value}"); attributeParams.Add(new CodeAttributeArgument(min)); } else { CodeSnippetExpression min = new CodeSnippetExpression($"{type.FullName}.MinValue"); attributeParams.Add(new CodeAttributeArgument(min)); } if (fieldSchema.Maximum.HasValue) { CodeSnippetExpression max = new CodeSnippetExpression($"{fieldSchema.Maximum.Value}"); attributeParams.Add(new CodeAttributeArgument(max)); } else { CodeSnippetExpression max = new CodeSnippetExpression($"{type.FullName}.MaxValue"); attributeParams.Add(new CodeAttributeArgument(max)); } CodeAttributeDeclaration cad = new CodeAttributeDeclaration("System.ComponentModel.DataAnnotations.Range", attributeParams.ToArray()); memberField.CustomAttributes.Add(cad); } if (fieldSchema.MinItems.HasValue) { CodeSnippetExpression len = new CodeSnippetExpression(fieldSchema.MinItems.Value.ToString()); CodeAttributeArgument[] attributeParams = new CodeAttributeArgument[] { new CodeAttributeArgument(len) }; CodeAttributeDeclaration cad = new CodeAttributeDeclaration("System.ComponentModel.DataAnnotations.MinLength", attributeParams); memberField.CustomAttributes.Add(cad); } if (fieldSchema.MaxItems.HasValue) { CodeSnippetExpression len = new CodeSnippetExpression(fieldSchema.MaxItems.Value.ToString()); CodeAttributeArgument[] attributeParams = new CodeAttributeArgument[] { new CodeAttributeArgument(len) }; CodeAttributeDeclaration cad = new CodeAttributeDeclaration("System.ComponentModel.DataAnnotations.MaxLength", attributeParams); memberField.CustomAttributes.Add(cad); } }
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); }