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;
        }
Ejemplo n.º 2
0
 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);
        }