private void EvaluateInheritance(Schema schema) { foreach (var subSchema in new SchemaEnumerator(schema)) { EvaluateInheritance(subSchema); } foreach (var typeReference in new TypeReferenceEnumerator(schema)) { if (typeReference.IsReference) { EvaluateInheritance(FileSchemas[typeReference.Name]); } } if (schema.AllOf == null) { return; } foreach (var typeRef in schema.AllOf) { var baseType = FileSchemas[typeRef.Name]; if (schema.Properties != null && baseType.Properties != null) { foreach (var property in baseType.Properties) { if (schema.Properties.TryGetValue(property.Key, out Schema value)) { if (value.IsEmpty()) { schema.Properties[property.Key] = property.Value; } else { throw new InvalidOperationException("Attempting to overwrite non-Default schema."); } } else { schema.Properties.Add(property.Key, property.Value); } } } foreach (var property in baseType.GetType().GetProperties()) { if (!property.CanRead || !property.CanWrite) { continue; } if (property.GetValue(schema) == null) { property.SetValue(schema, property.GetValue(baseType)); } } } schema.AllOf = null; }
public TypeReferenceEnumerator(Schema schema) { m_schema = schema; }
private static void EnforceRestrictionsOnSetValues(CodegenType returnType, string name, Schema schema) { if (schema.Minimum != null) { returnType.SetStatements.Add(new CodeConditionStatement { Condition = new CodeBinaryOperatorExpression { Left = new CodePropertySetValueReferenceExpression(), Operator = schema.ExclusiveMinimum ? CodeBinaryOperatorType.LessThanOrEqual : CodeBinaryOperatorType.LessThan, Right = new CodePrimitiveExpression(schema.Minimum) }, TrueStatements = { new CodeThrowExceptionStatement { ToThrow = new CodeObjectCreateExpression { CreateType = new CodeTypeReference(typeof(ArgumentOutOfRangeException)), Parameters = { new CodePrimitiveExpression(name), new CodePropertySetValueReferenceExpression(), new CodePrimitiveExpression( schema.ExclusiveMinimum ? $"Expected value to be greater than {schema.Minimum}" : $"Expected value to be greater than or equal to {schema.Minimum}") } } } } }); } if (schema.Maximum != null) { returnType.SetStatements.Add(new CodeConditionStatement { Condition = new CodeBinaryOperatorExpression { Left = new CodePropertySetValueReferenceExpression(), Operator = schema.ExclusiveMaximum ? CodeBinaryOperatorType.GreaterThanOrEqual : CodeBinaryOperatorType.GreaterThan, Right = new CodePrimitiveExpression(schema.Maximum) }, TrueStatements = { new CodeThrowExceptionStatement { ToThrow = new CodeObjectCreateExpression { CreateType = new CodeTypeReference(typeof(ArgumentOutOfRangeException)), Parameters = { new CodePrimitiveExpression(name), new CodePropertySetValueReferenceExpression(), new CodePrimitiveExpression( schema.ExclusiveMaximum ? $"Expected value to be less than {schema.Maximum}" : $"Expected value to be less than or equal to {schema.Maximum}") } } } } }); } if (schema.MinItems != null) { throw new NotImplementedException(); } if (schema.MinLength != null) { throw new NotImplementedException(); } if (schema.MaxItems != null) { throw new NotImplementedException(); } if (schema.MaxLength != null) { throw new NotImplementedException(); } }
public static CodegenType MakeCodegenType(string name, Schema schema) { CodegenType returnType = new CodegenType(); EnforceRestrictionsOnSetValues(returnType, name, schema); if (schema.Format == "uriref") { switch (schema.UriType) { case UriType.Application: case UriType.Image: case UriType.Text: returnType.CodeType = new CodeTypeReference(typeof(string)); returnType.AdditionalMembers.Add(Helpers.CreateMethodThatChecksIfTheValueOfAMemberIsNotEqualToAnotherExpression(name, new CodePrimitiveExpression(null))); break; case UriType.None: throw new InvalidDataException("UriType must be specified in the schema"); } return(returnType); } if (schema.Type.Count > 1) { returnType.CodeType = new CodeTypeReference(typeof(object)); returnType.AdditionalMembers.Add(Helpers.CreateMethodThatChecksIfTheValueOfAMemberIsNotEqualToAnotherExpression(name, new CodePrimitiveExpression(null))); return(returnType); } var typeRef = schema.Type[0]; if (typeRef.IsReference) { throw new NotImplementedException(); } if (typeRef.Name == "object") { if (schema.Enum != null || schema.Default != null) { throw new NotImplementedException(); } if (schema.Title != null) { returnType.CodeType = new CodeTypeReference(Helpers.ToPascalCase(schema.Title)); returnType.AdditionalMembers.Add(Helpers.CreateMethodThatChecksIfTheValueOfAMemberIsNotEqualToAnotherExpression(name, new CodePrimitiveExpression(null))); return(returnType); } throw new NotImplementedException(); } if (typeRef.Name == "number") { if (schema.Enum != null) { throw new NotImplementedException(); } if (schema.Default != null) { returnType.DefaultValue = new CodePrimitiveExpression(((JsonElement)schema.Default).GetSingle()); returnType.AdditionalMembers.Add(Helpers.CreateMethodThatChecksIfTheValueOfAMemberIsNotEqualToAnotherExpression(name, returnType.DefaultValue)); } else if (!schema.IsRequired) { returnType.CodeType = new CodeTypeReference(typeof(float?)); returnType.AdditionalMembers.Add(Helpers.CreateMethodThatChecksIfTheValueOfAMemberIsNotEqualToAnotherExpression(name, new CodePrimitiveExpression(null))); return(returnType); } returnType.CodeType = new CodeTypeReference(typeof(float)); return(returnType); } if (typeRef.Name == "string") { if (schema.Enum != null && !((string)schema.Enum[0]).Contains('/')) { returnType.Attributes.Add( new CodeAttributeDeclaration("System.Text.Json.Serialization.JsonConverterAttribute", new[] { new CodeAttributeArgument(new CodeTypeOfExpression(typeof(System.Text.Json.Serialization.JsonStringEnumConverter))) })); var enumType = GenStringEnumType(name, schema); returnType.AdditionalMembers.Add(enumType); if (schema.Default != null) { returnType.CodeType = new CodeTypeReference(enumType.Name); for (var i = 0; i < enumType.Members.Count; i++) { if (enumType.Members[i].Name.Equals(((JsonElement)schema.Default).GetString(), StringComparison.OrdinalIgnoreCase)) { returnType.DefaultValue = new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(enumType.Name), enumType.Members[i].Name); returnType.AdditionalMembers.Add(Helpers.CreateMethodThatChecksIfTheValueOfAMemberIsNotEqualToAnotherExpression(name, returnType.DefaultValue)); return(returnType); } } throw new InvalidDataException("The default value is not in the enum list"); } // TODO: System.Text.Json.Serialization.JsonStringEnumConverter cannot handle nullable enums. else if (!schema.IsRequired) { returnType.CodeType = new CodeTypeReference(typeof(Nullable <>)); returnType.CodeType.TypeArguments.Add(new CodeTypeReference(enumType.Name)); returnType.AdditionalMembers.Add(Helpers.CreateMethodThatChecksIfTheValueOfAMemberIsNotEqualToAnotherExpression(name, new CodePrimitiveExpression(null))); return(returnType); } returnType.CodeType = new CodeTypeReference(enumType.Name); return(returnType); } if (schema.Default != null) { returnType.DefaultValue = new CodePrimitiveExpression(((JsonElement)schema.Default).GetString()); returnType.AdditionalMembers.Add(Helpers.CreateMethodThatChecksIfTheValueOfAMemberIsNotEqualToAnotherExpression(name, returnType.DefaultValue)); } else { returnType.AdditionalMembers.Add(Helpers.CreateMethodThatChecksIfTheValueOfAMemberIsNotEqualToAnotherExpression(name, new CodePrimitiveExpression(null))); } returnType.CodeType = new CodeTypeReference(typeof(string)); return(returnType); } if (typeRef.Name == "integer") { if (schema.Enum != null) { var enumType = GenIntEnumType(name, schema); returnType.AdditionalMembers.Add(enumType); if (schema.Default != null) { returnType.DefaultValue = GetEnumField(enumType, ((JsonElement)schema.Default).GetInt32()); returnType.AdditionalMembers.Add(Helpers.CreateMethodThatChecksIfTheValueOfAMemberIsNotEqualToAnotherExpression(name, returnType.DefaultValue)); } else if (!schema.IsRequired) { returnType.CodeType = new CodeTypeReference(typeof(Nullable <>)); returnType.CodeType.TypeArguments.Add(new CodeTypeReference(enumType.Name)); returnType.AdditionalMembers.Add(Helpers.CreateMethodThatChecksIfTheValueOfAMemberIsNotEqualToAnotherExpression(name, new CodePrimitiveExpression(null))); return(returnType); } returnType.CodeType = new CodeTypeReference(enumType.Name); return(returnType); } if (schema.Default != null) { returnType.DefaultValue = new CodePrimitiveExpression(((JsonElement)schema.Default).GetInt32()); returnType.AdditionalMembers.Add(Helpers.CreateMethodThatChecksIfTheValueOfAMemberIsNotEqualToAnotherExpression(name, returnType.DefaultValue)); } else if (!schema.IsRequired) { returnType.CodeType = new CodeTypeReference(typeof(int?)); returnType.AdditionalMembers.Add(Helpers.CreateMethodThatChecksIfTheValueOfAMemberIsNotEqualToAnotherExpression(name, new CodePrimitiveExpression(null))); return(returnType); } returnType.CodeType = new CodeTypeReference(typeof(int)); return(returnType); } if (typeRef.Name == "boolean") { if (schema.Enum != null) { throw new NotImplementedException(); } if (schema.Default != null) { returnType.DefaultValue = new CodePrimitiveExpression(((JsonElement)schema.Default).GetBoolean()); returnType.AdditionalMembers.Add(Helpers.CreateMethodThatChecksIfTheValueOfAMemberIsNotEqualToAnotherExpression(name, returnType.DefaultValue)); } else if (!schema.IsRequired) { returnType.CodeType = new CodeTypeReference(typeof(bool?)); returnType.AdditionalMembers.Add(Helpers.CreateMethodThatChecksIfTheValueOfAMemberIsNotEqualToAnotherExpression(name, new CodePrimitiveExpression(null))); return(returnType); } returnType.CodeType = new CodeTypeReference(typeof(bool)); return(returnType); } // other types: array, null throw new NotImplementedException(typeRef.Name); }
private static void EnforceRestrictionsOnSetValues(CodegenType returnType, string name, Schema schema) { if (schema.MinItems != null) { returnType.SetStatements.Add(new CodeConditionStatement { Condition = new CodeBinaryOperatorExpression { Left = new CodePropertyReferenceExpression(new CodePropertySetValueReferenceExpression(), "Length"), Operator = CodeBinaryOperatorType.LessThan, Right = new CodePrimitiveExpression(schema.MinItems) }, TrueStatements = { new CodeThrowExceptionStatement(new CodeObjectCreateExpression(typeof(ArgumentException), new CodeExpression[] { new CodePrimitiveExpression("Array not long enough") })) } }); } if (schema.MaxItems != null) { returnType.SetStatements.Add(new CodeConditionStatement { Condition = new CodeBinaryOperatorExpression { Left = new CodePropertyReferenceExpression(new CodePropertySetValueReferenceExpression(), "Length"), Operator = CodeBinaryOperatorType.GreaterThan, Right = new CodePrimitiveExpression(schema.MaxItems) }, TrueStatements = { new CodeThrowExceptionStatement(new CodeObjectCreateExpression(typeof(ArgumentException), new CodeExpression[] { new CodePrimitiveExpression("Array too long") })) } }); } if (schema.Items.Minimum != null || schema.Items.Maximum != null || schema.Items.MinLength != null || schema.Items.MaxLength != null) { returnType.SetStatements.Add(new CodeVariableDeclarationStatement(typeof(int), "index", new CodePrimitiveExpression(0))); } if (schema.Items.Minimum != null) { returnType.SetStatements.Add(LoopThroughArray(new CodePropertySetValueReferenceExpression(), new CodeStatementCollection { new CodeConditionStatement { Condition = new CodeBinaryOperatorExpression { Left = new CodeArrayIndexerExpression { TargetObject = new CodePropertySetValueReferenceExpression(), Indices = { new CodeVariableReferenceExpression("index") }, }, Operator = schema.Items.ExclusiveMinimum ? CodeBinaryOperatorType.LessThanOrEqual : CodeBinaryOperatorType.LessThan, Right = new CodePrimitiveExpression(schema.Items.Minimum) }, TrueStatements = { new CodeThrowExceptionStatement(new CodeObjectCreateExpression(typeof(ArgumentOutOfRangeException))) } } })); } if (schema.Items.Maximum != null) { returnType.SetStatements.Add(LoopThroughArray(new CodePropertySetValueReferenceExpression(), new CodeStatementCollection { new CodeConditionStatement { Condition = new CodeBinaryOperatorExpression { Left = new CodeArrayIndexerExpression { TargetObject = new CodePropertySetValueReferenceExpression(), Indices = { new CodeVariableReferenceExpression("index") }, }, Operator = schema.Items.ExclusiveMaximum ? CodeBinaryOperatorType.GreaterThanOrEqual : CodeBinaryOperatorType.GreaterThan, Right = new CodePrimitiveExpression(schema.Items.Maximum) }, TrueStatements = { new CodeThrowExceptionStatement(new CodeObjectCreateExpression(typeof(ArgumentOutOfRangeException))) } } })); } if (schema.Items.MinLength != null) { returnType.SetStatements.Add(LoopThroughArray(new CodePropertySetValueReferenceExpression(), new CodeStatementCollection { new CodeConditionStatement { Condition = new CodeBinaryOperatorExpression { Left = new CodePropertyReferenceExpression(new CodeArrayIndexerExpression { TargetObject = new CodePropertySetValueReferenceExpression(), Indices = { new CodeVariableReferenceExpression("index") }, }, "Length"), Operator = CodeBinaryOperatorType.LessThan, Right = new CodePrimitiveExpression(schema.Items.MinLength) }, TrueStatements = { new CodeThrowExceptionStatement(new CodeObjectCreateExpression(typeof(ArgumentException))) } } })); } if (schema.Items.MaxLength != null) { returnType.SetStatements.Add(LoopThroughArray(new CodePropertySetValueReferenceExpression(), new CodeStatementCollection { new CodeConditionStatement { Condition = new CodeBinaryOperatorExpression { Left = new CodePropertyReferenceExpression(new CodeArrayIndexerExpression { TargetObject = new CodePropertySetValueReferenceExpression(), Indices = { new CodeVariableReferenceExpression("index") }, }, "Length"), Operator = CodeBinaryOperatorType.GreaterThan, Right = new CodePrimitiveExpression(schema.Items.MaxLength) }, TrueStatements = { new CodeThrowExceptionStatement(new CodeObjectCreateExpression(typeof(ArgumentException))) } } })); } }
public static CodegenType MakeCodegenType(string name, Schema Schema) { if (!(Schema.Items?.Type?.Length > 0)) { throw new InvalidOperationException("Array type must contain an item type"); } if (Schema.Enum != null) { throw new InvalidOperationException(); } if (Schema.Items.Disallowed != null) { throw new NotImplementedException(); } var returnType = new CodegenType(); returnType.Attributes.Add(new CodeAttributeDeclaration("Newtonsoft.Json.JsonConverterAttribute", new [] { new CodeAttributeArgument(new CodeTypeOfExpression(typeof(ArrayConverter))) })); if (Schema.Items.Type.Length > 1) { returnType.CodeType = new CodeTypeReference(typeof(object[])); returnType.AdditionalMembers.Add(Helpers.CreateMethodThatChecksIfTheValueOfAMemberIsNotEqualToAnotherExpression(name, new CodePrimitiveExpression(null))); return(returnType); } EnforceRestrictionsOnSetValues(returnType, name, Schema); if (Schema.Items.Type[0].Name == "integer") { if (Schema.Items.Enum != null) { var enumType = SingleValueCodegenTypeFactory.GenIntEnumType(name, Schema.Items); returnType.AdditionalMembers.Add(enumType); if (Schema.HasDefaultValue()) { var defaultValueArray = ((JArray)Schema.Default).Select(x => (CodeExpression)SingleValueCodegenTypeFactory.GetEnumField(enumType, (int)(long)x)).ToArray(); returnType.DefaultValue = new CodeArrayCreateExpression(enumType.Name, defaultValueArray); returnType.AdditionalMembers.Add(Helpers.CreateMethodThatChecksIfTheArrayOfValueOfAMemberIsNotEqualToAnotherExpression(name, returnType.DefaultValue)); } else { returnType.AdditionalMembers.Add(Helpers.CreateMethodThatChecksIfTheValueOfAMemberIsNotEqualToAnotherExpression(name, new CodePrimitiveExpression(null))); } returnType.CodeType = new CodeTypeReference(enumType.Name + "[]"); return(returnType); } if (Schema.HasDefaultValue()) { var defaultValueArray = ((JArray)Schema.Default).Select( x => (CodeExpression) new CodePrimitiveExpression((int)(long)x)).ToArray(); returnType.DefaultValue = new CodeArrayCreateExpression(typeof(int), defaultValueArray); returnType.AdditionalMembers.Add(Helpers.CreateMethodThatChecksIfTheArrayOfValueOfAMemberIsNotEqualToAnotherExpression(name, returnType.DefaultValue)); } else { returnType.AdditionalMembers.Add(Helpers.CreateMethodThatChecksIfTheValueOfAMemberIsNotEqualToAnotherExpression(name, new CodePrimitiveExpression(null))); } returnType.CodeType = new CodeTypeReference(typeof(int[])); return(returnType); } if (Schema.Items.Enum != null) { throw new NotImplementedException(); } if (Schema.Items.Type[0].Name == "number") { if (Schema.HasDefaultValue()) { var defaultVauleArray = (JArray)Schema.Default; returnType.DefaultValue = new CodeArrayCreateExpression(typeof(float), defaultVauleArray.Select(x => (CodeExpression) new CodePrimitiveExpression((float)x)).ToArray()); returnType.AdditionalMembers.Add(Helpers.CreateMethodThatChecksIfTheArrayOfValueOfAMemberIsNotEqualToAnotherExpression(name, returnType.DefaultValue)); } else { returnType.AdditionalMembers.Add(Helpers.CreateMethodThatChecksIfTheValueOfAMemberIsNotEqualToAnotherExpression(name, new CodePrimitiveExpression(null))); } returnType.CodeType = new CodeTypeReference(typeof(float[])); return(returnType); } if (Schema.Items.Minimum != null || Schema.Items.Maximum != null) { throw new NotImplementedException(); } if (Schema.Items.Type[0].Name == "boolean") { if (Schema.HasDefaultValue()) { var defaultVauleArray = (JArray)Schema.Default; returnType.DefaultValue = new CodeArrayCreateExpression(typeof(bool), defaultVauleArray.Select(x => (CodeExpression) new CodePrimitiveExpression((bool)x)).ToArray()); returnType.AdditionalMembers.Add(Helpers.CreateMethodThatChecksIfTheArrayOfValueOfAMemberIsNotEqualToAnotherExpression(name, returnType.DefaultValue)); } else { returnType.AdditionalMembers.Add(Helpers.CreateMethodThatChecksIfTheValueOfAMemberIsNotEqualToAnotherExpression(name, new CodePrimitiveExpression(null))); } returnType.CodeType = new CodeTypeReference(typeof(bool[])); return(returnType); } if (Schema.Items.Type[0].Name == "string") { if (Schema.HasDefaultValue()) { var defaultVauleArray = (JArray)Schema.Default; returnType.DefaultValue = new CodeArrayCreateExpression(typeof(string), defaultVauleArray.Select(x => (CodeExpression) new CodePrimitiveExpression((string)x)) .ToArray()); returnType.AdditionalMembers.Add(Helpers.CreateMethodThatChecksIfTheArrayOfValueOfAMemberIsNotEqualToAnotherExpression(name, returnType.DefaultValue)); } else { returnType.AdditionalMembers.Add(Helpers.CreateMethodThatChecksIfTheValueOfAMemberIsNotEqualToAnotherExpression(name, new CodePrimitiveExpression(null))); } returnType.CodeType = new CodeTypeReference(typeof(string[])); return(returnType); } if (Schema.Items.Type[0].Name == "object") { if (Schema.HasDefaultValue()) { throw new NotImplementedException("Array of Objects has default value"); } if (Schema.Items.Title != null) { returnType.CodeType = new CodeTypeReference(Helpers.ParseTitle(Schema.Items.Title) + "[]"); returnType.AdditionalMembers.Add(Helpers.CreateMethodThatChecksIfTheValueOfAMemberIsNotEqualToAnotherExpression(name, new CodePrimitiveExpression(null))); returnType.Attributes.Clear(); if (Schema.MinItems != null || Schema.MaxItems != null || Schema.Items.MinLength != null || Schema.Items.MaxLength != null) { throw new NotImplementedException(); } return(returnType); } if (Schema.Items.DictionaryValueType != null) { throw new NotImplementedException(); } returnType.CodeType = new CodeTypeReference(typeof(object[])); returnType.AdditionalMembers.Add(Helpers.CreateMethodThatChecksIfTheValueOfAMemberIsNotEqualToAnotherExpression(name, new CodePrimitiveExpression(null))); return(returnType); } throw new NotImplementedException("Array of " + Schema.Items.Type[0].Name); }