<commit_before>//
//  Definition.swift
//  SwagGen
//
//  Created by <NAME> on 18/2/17.
//
//

import Foundation
import JSONUtilities

public class Schema: JSONObjectConvertible {

    public var name: String?
    public let type: String?
    public let description: String?
    public var reference: String?
    public var parentReference: String?
    public var parent: Schema?
    public var propertiesByName: [String: Property]
    public let requiredProperties: [Property]
    public let optionalProperties: [Property]
    public let properties: [Property]
    public let json: JSONDictionary
    public var anonymous: Bool = false
    public var additionalProperties: Either<Value, Bool>

    required public init(jsonDictionary: JSONDictionary) throws {
        self.json = jsonDictionary
        var json = jsonDictionary
        if let allOf = json.json(atKeyPath: "allOf") as [JSONDictionary]? {
            parentReference = allOf[0].json(atKeyPath: "$ref")
            json = allOf[1]
        }
        type = json.json(atKeyPath: "type")
        reference = json.json(atKeyPath: "$ref")
        description = json.json(atKeyPath: "description")
        propertiesByName = json.json(atKeyPath: "properties") ?? [:]
        propertiesByName.forEach { name, property in
            property.name = name
            if let value = property.arrayValue, value.name.isEmpty {
                value.name = name
            }
            if let value = property.dictionaryValue, value.name.isEmpty {
                value.name = name
            }
        }

        var requiredProperties: [Property] = []
        if let required = json.json(atKeyPath: "required") as [String]? {
            for propertyName in required {
                if let property = propertiesByName[propertyName] {
                    property.required = true
                    requiredProperties.append(property)
                }
            }
        }
        self.requiredProperties = requiredProperties
        optionalProperties = Array(propertiesByName.values).filter { !$0.required }.sorted{$0.name < $1.name}
        properties = requiredProperties + optionalProperties

        if let schema = jsonDictionary.json(atKeyPath: "additionalProperties") as Value? {
            additionalProperties = .a(schema)
        } else {
            let bool: Bool = jsonDictionary.json(atKeyPath: "additionalProperties") ?? false
            additionalProperties = .b(bool)
        }
    }

    public var allProperties: [Property] {
        return (parent?.allProperties ?? []) + properties
    }

    func deepDescription(prefix: String) -> String {
        return "\(prefix)\(name ?? "")\n\(prefix)\(properties.map { $0.deepDescription(prefix: prefix) }.joined(separator: "\n\(prefix)"))"
    }

    public var enums: [Value] {
        var enums: [Value] = properties.filter { $0.isEnum }

        if case.a(let additionalSchema) = additionalProperties, additionalSchema.isEnum {
            enums.append(additionalSchema)
        }

        return enums
    }
}

public class Property: Value {
}<commit_msg>changed property order so all required are first<commit_after>//
//  Definition.swift
//  SwagGen
//
//  Created by <NAME> on 18/2/17.
//
//

import Foundation
import JSONUtilities

public class Schema: JSONObjectConvertible {

    public var name: String?
    public let type: String?
    public let description: String?
    public var reference: String?
    public var parentReference: String?
    public var parent: Schema?
    public var propertiesByName: [String: Property]
    public let requiredProperties: [Property]
    public let optionalProperties: [Property]
    public let properties: [Property]
    public let json: JSONDictionary
    public var anonymous: Bool = false
    public var additionalProperties: Either<Value, Bool>

    required public init(jsonDictionary: JSONDictionary) throws {
        self.json = jsonDictionary
        var json = jsonDictionary
        if let allOf = json.json(atKeyPath: "allOf") as [JSONDictionary]? {
            parentReference = allOf[0].json(atKeyPath: "$ref")
            json = allOf[1]
        }
        type = json.json(atKeyPath: "type")
        reference = json.json(atKeyPath: "$ref")
        description = json.json(atKeyPath: "description")
        propertiesByName = json.json(atKeyPath: "properties") ?? [:]
        propertiesByName.forEach { name, property in
            property.name = name
            if let value = property.arrayValue, value.name.isEmpty {
                value.name = name
            }
            if let value = property.dictionaryValue, value.name.isEmpty {
                value.name = name
            }
        }

        var requiredProperties: [Property] = []
        if let required = json.json(atKeyPath: "required") as [String]? {
            for propertyName in required {
                if let property = propertiesByName[propertyName] {
                    property.required = true
                    requiredProperties.append(property)
                }
            }
        }
        self.requiredProperties = requiredProperties
        optionalProperties = Array(propertiesByName.values).filter { !$0.required }.sorted{$0.name < $1.name}
        properties = requiredProperties + optionalProperties

        if let schema = jsonDictionary.json(atKeyPath: "additionalProperties") as Value? {
            additionalProperties = .a(schema)
        } else {
            let bool: Bool = jsonDictionary.json(atKeyPath: "additionalProperties") ?? false
            additionalProperties = .b(bool)
        }
    }

    private var allRequiredProperties: [Property] {
        return (parent?.allRequiredProperties ?? []) + requiredProperties
    }

    private var allOptionalProperties: [Property] {
        return (parent?.allOptionalProperties ?? []) + optionalProperties
    }

    public var allProperties: [Property] {
        return allRequiredProperties + allOptionalProperties
    }

    func deepDescription(prefix: String) -> String {
        return "\(prefix)\(name ?? "")\n\(prefix)\(properties.map { $0.deepDescription(prefix: prefix) }.joined(separator: "\n\(prefix)"))"
    }

    public var enums: [Value] {
        var enums: [Value] = properties.filter { $0.isEnum }

        if case.a(let additionalSchema) = additionalProperties, additionalSchema.isEnum {
            enums.append(additionalSchema)
        }

        return enums
    }
}

public class Property: Value {
}
{'fraction_non_alphanumeric': 0.10083256244218317, 'fraction_numerical': 0.0037002775208140612, 'mean_word_length': 2.4124145186743817, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6316335', 'n_tokens_mistral': 1699, 'n_tokens_neox': 1647, 'n_words': 447}