예제 #1
0
        private static void ReplaceRefs(JSONSchema schema, JSONSchema root)
        {
            ReplaceRefsInDictionary(schema.Properties, root);
            ReplaceRefsInDictionary(schema.Definitions, root);
            ReplaceRefsInDictionary(schema.PatternProperties, root);

            if (schema.AdditionalProperties != null)
            {
                ReplaceRefsInAnyOf <bool, JSONSchema>(schema.AdditionalProperties, root);
            }
            if (schema.AdditionalItems != null)
            {
                ReplaceRefsInAnyOf <bool, JSONSchema>(schema.AdditionalItems, root);
            }
            if (schema.Items != null)
            {
                ReplaceRefsInAnyOf <JSONSchema, SchemaArray>(schema.Items, root);
            }

            ReplaceRefsInSchemaArray(schema.AnyOf, root);
            ReplaceRefsInSchemaArray(schema.AllOf, root);
            ReplaceRefsInSchemaArray(schema.OneOf, root);



            if (schema.Not?.Ref != null)
            {
                schema.Not = convertRefToSchema(schema.Not.Ref, root);
            }
        }
예제 #2
0
 private static void ReplaceRefsInSchemaArray(SchemaArray array, JSONSchema root)
 {
     if (array?.Count > 0)
     {
         for (int i = 0; i < array.Count; i++)
         {
             if (array[i]?.Ref != null)
             {
                 array[i] = convertRefToSchema(array[i].Ref, root);
             }
             else
             {
                 ReplaceRefs(array[i], root);
             }
         }
     }
 }
예제 #3
0
        private Type ComputeType(JSONSchema schema)
        {
            if (schema.Type?.GetUnderlyingType() == typeof(SimpleType))
            {
                var simpleType = schema.Type.Value as SimpleType;
                switch (simpleType.Value)
                {
                case SimpleType.Boolean:
                    return(typeof(Boolean));

                case SimpleType.String:
                    return(typeof(string));

                case SimpleType.Integer:
                    return(typeof(Int32));

                case SimpleType.Number:
                    return(typeof(Decimal));

                case SimpleType.Object:
                    return(typeof(object));

                case SimpleType.Array:
                    if (schema.Items?.Value is JSONSchema)
                    {
                        var itemsSchema = schema.Items.Value as JSONSchema;
                        if (context.ContainsKey(itemsSchema))
                        {
                            return(typeof(List <>).MakeGenericType(context[itemsSchema].Type));
                        }
                        else
                        {
                            return(typeof(List <>).MakeGenericType(ComputeType(itemsSchema)));
                        }
                    }
                    return(typeof(IList));

                default:
                    return(typeof(object));
                }
            }

            return(typeof(object));
        }
예제 #4
0
 private static JSONSchema convertRefToSchema(string @ref, JSONSchema root)
 {
     if (@ref.Equals("#"))
     {
         return(root);
     }
     else
     {
         var paths = @ref.Split('/');
         if (paths.Length == 3 && paths[0].Equals("#") && paths[1].Equals("definitions"))
         {
             return(root.Definitions[paths[2]]);
         }
         else
         {
             throw new NotImplementedException("this type of reference is not supported");
         }
     }
 }
예제 #5
0
        private static void ReplaceRefsInAnyOf <T1, T2>(AnyOf <T1, T2> anyOf, JSONSchema root)
        {
            if (anyOf?.GetValue() is JSONSchema)
            {
                var anyOfSchema = (JSONSchema)anyOf.GetValue();
                if (anyOfSchema?.Ref != null)
                {
                    anyOf.ChangeValue(convertRefToSchema(anyOfSchema.Ref, root));
                }
                else
                {
                    ReplaceRefs(anyOfSchema, root);
                }
            }

            if (anyOf?.GetValue() is SchemaArray)
            {
                var anyOfSchema = (SchemaArray)anyOf.GetValue();
                ReplaceRefsInSchemaArray(anyOfSchema, root);
            }
        }
예제 #6
0
        public static JSONSchema MergeSchemas(SchemaArray schemas)
        {
            JSONSchema result = new JSONSchema();

            //handle recursivity
            schemas = new SchemaArray(
                schemas.Where(x => x.AllOf == null || !x.AllOf.Any())
                .Union(
                    schemas.Where(x => x.AllOf != null && x.AllOf.Any())
                    .Select(x => MergeSchemas(x.AllOf))).ToList());

            //This won't raise an exception if different (incompatible) types are defined
            result.Type = schemas.Where(x => x.Type != null).Select(x => x.Type).FirstOrDefault();

            var multiples = schemas.Where(x => x.MultipleOf.HasValue).Select(x => x.MultipleOf.Value);

            if (multiples.Any())
            {
                result.MultipleOf = multiples.Aggregate((uint)1, (lcm, next) => LCM(lcm, next));
            }

            var max = schemas.Where(x => x.Maximum.HasValue).Select(x => x.Maximum);

            if (max.Any())
            {
                result.Maximum          = max.Min();
                result.ExclusiveMaximum = schemas.Where(x => x.ExclusiveMaximum.HasValue && x.Maximum == result.Maximum).Select(x => x.ExclusiveMaximum).FirstOrDefault();
            }

            var min = schemas.Where(x => x.Mininum.HasValue).Select(x => x.Mininum);

            if (min.Any())
            {
                result.Mininum          = min.Max();
                result.ExclusiveMinimum = schemas.Where(x => x.ExclusiveMinimum.HasValue && x.Mininum == result.Mininum).Select(x => x.ExclusiveMinimum).FirstOrDefault();
            }

            var maxLength = schemas.Where(x => x.MaxLength.HasValue).Select(x => x.MaxLength);

            if (maxLength.Any())
            {
                result.MaxLength = maxLength.Min();
            }

            var minLength = schemas.Where(x => x.MinLength.HasValue).Select(x => x.MinLength);

            if (minLength.Count() > 0)
            {
                result.MinLength = minLength.Max();
            }

            var patterns = schemas.Where(x => !string.IsNullOrEmpty(x.Pattern)).Select(x => x.Pattern);

            if (patterns.Any())
            {
                result.Pattern = string.Concat(patterns.Select(x => string.Format("(?={0})", x)));
            }


            //TODO: items

            var maxItems = schemas.Where(x => x.MaxItems.HasValue).Select(x => x.MaxItems);

            if (maxItems.Any())
            {
                result.MaxItems = maxItems.Min();
            }

            var minItems = schemas.Where(x => x.MinItems.HasValue).Select(x => x.MinItems);

            if (minItems.Any())
            {
                result.MinItems = minItems.Max();
            }

            var properties = schemas.Where(x => x.Properties != null && x.Properties.Any()).Select(x => x.Properties);

            if (properties.Any())
            {
                result.Properties = properties.SelectMany(dict => dict)
                                    .ToLookup(pair => pair.Key, pair => pair.Value)
                                    .ToDictionary(group => group.Key, group => group.First());
            }

            return(result);
        }
예제 #7
0
 private static void ReplaceRefsInDictionary(Dictionary <string, JSONSchema> dictionary, JSONSchema root)
 {
     if (dictionary != null)
     {
         var keyList = new List <string>(dictionary.Keys);
         foreach (string property in keyList)
         {
             if (dictionary[property]?.Ref != null)
             {
                 dictionary[property] = convertRefToSchema(dictionary[property].Ref, root);
             }
             else
             {
                 ReplaceRefs(dictionary[property], root);
             }
         }
     }
 }
예제 #8
0
        private Type GetEnumType(JSONSchema schema)
        {
            if (schema.Type != null && schema.Type.Value is SimpleType)
            {
                return(ComputeType(schema));
            }

            if (schema.Type == null)
            {
                HashSet <JsonValueKind> types = new HashSet <JsonValueKind>();
                foreach (JsonElement enumValue in schema.Enum)
                {
                    types.Add(enumValue.ValueKind);
                }
                if (types.Count() == 1)
                {
                    switch (types.First())
                    {
                    case JsonValueKind.String: return(typeof(string));

                    case JsonValueKind.Number: return(NumberDefaultType);

                    case JsonValueKind.True:
                    case JsonValueKind.False:
                        return(typeof(bool));

                    default:
                        return(typeof(object));
                    }
                }
                if (types.Count() == 2)
                {
                    if (types.Contains(JsonValueKind.False) && types.Contains(JsonValueKind.True))
                    {
                        return(typeof(bool));
                    }
                    if (types.Contains(JsonValueKind.Null))
                    {
                        switch (types.Where(x => x != JsonValueKind.Null).First())
                        {
                        case JsonValueKind.String: return(typeof(string));    //strings can null

                        case JsonValueKind.Number: return(typeof(Nullable <>).MakeGenericType(NumberDefaultType));

                        case JsonValueKind.True:
                        case JsonValueKind.False:
                            return(typeof(Nullable <>).MakeGenericType(typeof(bool)));

                        default:
                            return(typeof(object));   //objects can be null
                        }
                    }
                }
                if (types.Count() == 3)
                {
                    if (types.IsSubsetOf(new List <JsonValueKind> {
                        JsonValueKind.Null, JsonValueKind.False, JsonValueKind.True
                    }))
                    {
                        return(typeof(Nullable <>).MakeGenericType(typeof(bool)));
                    }
                }
            }
            return(typeof(object));
        }
예제 #9
0
        private CodeTypeDeclaration GenerateClass()
        {
            if (!context.ContainsKey(schema))
            {
                context.Add(schema, new GenerationResult()
                {
                    TypeName       = targetClass.Name,
                    Type           = MyTypeBuilder.CreateType(targetClass.Name),
                    ClassGenerator = this
                });
            }

            if (schema.Enum?.Count > 0)
            {
                return(GenerateClassFromEnumSchema());
            }

            if (schema.Type?.Value is SimpleType && (schema.Type.Value as SimpleType).Value != SimpleType.Object)
            {
                var schemaType = schema.Type.Value as SimpleType;
                if (schemaType.Value == SimpleType.Integer)
                {
                    return(GenerateClassFromIntegerSchema());
                }

                if (schemaType.Value == SimpleType.Number)
                {
                    return(GenerateClassFromNumberSchema());
                }

                if (schemaType.Value == SimpleType.String)
                {
                    return(GenerateClassFromStringSchema());
                }

                if (schemaType.Value == SimpleType.Array)
                {
                    return(GenerateClassFromArraySchema());
                }
            }
            var definitions = schema.Definitions;

            if (definitions != null)
            {
                foreach (string definitionName in schema.Definitions.Keys)
                {
                    var definition = definitions[definitionName];
                    if (!context.ContainsKey(definition))
                    {
                        var nestedClassGenerator = new ClassGeneratorFromJsonSchema(definition, context);
                        context[definition] = new GenerationResult()
                        {
                            Type           = MyTypeBuilder.CreateType(nestedClassGenerator.targetClass.Name),
                            TypeName       = nestedClassGenerator.targetClass.Name,
                            ClassGenerator = nestedClassGenerator
                        };
                        nestedClassGenerator.GenerateClass();
                    }
                    //context.Add(definition, new GenerationResult() { TypeName = nestedClassGenerator.targetClass.Name });
                }
            }

            var properties           = schema.Properties;
            var additionalProperties = schema.AdditionalProperties;

            //Oneof/AnyOf/AllOf are only supported when there are no properties or additionalProperties and when the schema type is not a primitive type or array type
            if (properties == null && additionalProperties == null)
            {
                if (schema.OneOf != null && schema.OneOf.Count > 0)
                {
                    return(GenerateClassFromOneOfAnyOfSchema(true));
                }

                if (schema.AnyOf != null && schema.AnyOf.Count > 0)
                {
                    return(GenerateClassFromOneOfAnyOfSchema(false));
                }

                if (schema.AllOf != null && schema.AllOf.Count > 0)
                {
                    var mergedSchema         = JSONSchema.MergeSchemas(schema.AllOf);
                    var mergedClassGenerator = new ClassGeneratorFromJsonSchema(mergedSchema, this.targetClass.Name);
                    targetClass     = mergedClassGenerator.GenerateClass();
                    context[schema] = mergedClassGenerator.context[mergedSchema];
                    foreach (var jsonSchema in mergedClassGenerator.context.Keys)
                    {
                        if (jsonSchema != mergedSchema)
                        {
                            context[jsonSchema] = mergedClassGenerator.context[jsonSchema];
                        }
                    }
                    return(targetClass);
                }
            }

            if (properties != null)
            {
                foreach (string propertyName in properties.Keys)
                {
                    var cleanPropertyName = Clean(propertyName);
                    if (propertyNames.Contains(cleanPropertyName))
                    {
                        //to avoid property names that would collide
                        continue;
                    }
                    propertyNames.Add(cleanPropertyName);
                    var property = properties[propertyName];

                    if (context.ContainsKey(property))
                    {
                        targetClass.AddProperty(cleanPropertyName, context[property].TypeName);
                    }
                    else if (property.Type?.GetUnderlyingType() == typeof(SimpleType) &&
                             (property.Type.Value as SimpleType).Value != SimpleType.Object &&
                             (property.Type.Value as SimpleType).Value != SimpleType.Array &&
                             (property.Enum == null || property.Enum.Count < 1)
                             )
                    {
                        targetClass.AddProperty(cleanPropertyName, ComputeType((SimpleType)property.Type.GetValue()));
                    }
                    else
                    {
                        var nestedClassGenerator = new ClassGeneratorFromJsonSchema(property, context, cleanPropertyName);
                        context[property] = new GenerationResult()
                        {
                            Type           = MyTypeBuilder.CreateType(nestedClassGenerator.targetClass.Name),
                            TypeName       = nestedClassGenerator.targetClass.Name,
                            ClassGenerator = nestedClassGenerator
                        };
                        nestedClassGenerator.GenerateClass();
                        targetClass.AddProperty(cleanPropertyName, context[property].Type);
                    }
                }
            }


            if (additionalProperties != null)
            {
                if (additionalProperties.Value is bool)
                {
                    if ((bool)additionalProperties.Value == true)
                    {
                        targetClass.BaseTypes.Add(new CodeTypeReference(typeof(Dictionary <string, object>)));
                    }
                }
                else
                {
                    var additionalPropertiesSchema = additionalProperties.Value as JSONSchema;
                    if (!context.ContainsKey(additionalPropertiesSchema))
                    {
                        var nestedClassGenerator = new ClassGeneratorFromJsonSchema(additionalPropertiesSchema, context, context[schema].TypeName + "AdditionalProperties");
                        context[additionalPropertiesSchema] = new GenerationResult()
                        {
                            Type           = MyTypeBuilder.CreateType(nestedClassGenerator.targetClass.Name),
                            TypeName       = nestedClassGenerator.targetClass.Name,
                            ClassGenerator = nestedClassGenerator
                        };
                        nestedClassGenerator.GenerateClass();
                    }
                    targetClass.BaseTypes.Add(new CodeTypeReference("Dictionary", new CodeTypeReference(typeof(string)), new CodeTypeReference(context[additionalPropertiesSchema].Type)));
                    context[schema].Imports.Add("System.Collections.Generic");
                }
            }



            return(targetClass);
        }
예제 #10
0
 private ClassGeneratorFromJsonSchema(JSONSchema schema, Dictionary <JSONSchema, GenerationResult> context, string title = null) : base(title ?? schema.Title)
 {
     this.schema  = schema;
     this.context = context;
 }
예제 #11
0
 public ClassGeneratorFromJsonSchema(JSONSchema schema, string title = null) : base(title ?? schema.Title)
 {
     this.schema = schema;
     context     = new Dictionary <JSONSchema, GenerationResult>();
 }