<commit_before>//
//  swift-code-generation.swift
//  json2swift
//
//  Created by <NAME> on 10/14/16.
//  Copyright © 2016 iJoshSmith. All rights reserved.
//

import Foundation

struct SwiftCodeGenerator {
    /// This method is used when only one Swift file is being generated.
    static func generateCodeWithJSONUtilities(for swiftStruct: SwiftStruct) -> String {
        return [
            "// This file was generated by json2swift.",
            "",
            "import Foundation",
            "",
            "//",
            "// MARK: - Data Model",
            "//",
            swiftStruct.toSwiftCode(),
            "",
            "//",
            "// MARK: - JSON Utilities",
            "//",
            jsonUtilitiesTemplate,
            ""].joined(separator: "\n")
    }
    
    /// This method is used when multiple Swift files are being generated.
    static func generateCode(for swiftStruct: SwiftStruct) -> String {
        return [
            "// This file was generated by json2swift.",
            "",
            "import Foundation",
            "",
            swiftStruct.toSwiftCode(),
            ""].joined(separator: "\n")
    }
    
    /// This method is used to only create the JSON utility code once when multiple Swift files are being generated.
    static func generateJSONUtilities() -> String {
        return [
            "// This file was generated by json2swift.",
            "",
            "import Foundation",
            "",
            jsonUtilitiesTemplate,
            ""].joined(separator: "\n")
    }
}


// MARK: - Implementation

typealias SwiftCode = String
typealias LineOfCode = SwiftCode

fileprivate struct Indentation {
    private let chars: String
    private let level: Int
    private let value: String
    
    init(chars: String, level: Int = 0) {
        precondition(level >= 0)
        self.chars = chars
        self.level = level
        self.value = String(repeating: chars, count: level)
    }
    
    func apply(toLineOfCode lineOfCode: LineOfCode) -> LineOfCode {
        return value + lineOfCode
    }
    
    func apply(toFirstLine firstLine: LineOfCode,
               nestedLines generateNestedLines: (Indentation) -> [LineOfCode],
               andLastLine lastLine: LineOfCode) -> [LineOfCode] {
        let first  = apply(toLineOfCode: firstLine)
        let middle = generateNestedLines(self.increased())
        let last   = apply(toLineOfCode: lastLine)
        return [first] + middle + [last]
    }
    
    private func increased() -> Indentation {
        return Indentation(chars: chars, level: level + 1)
    }
}

fileprivate extension SwiftStruct {
    func toSwiftCode(indentedBy indentChars: String = "    ") -> SwiftCode {
        let indentation = Indentation(chars: indentChars)
        let linesOfCode = toLinesOfCode(at: indentation)
        return linesOfCode.joined(separator: "\n")
    }
    
    private func toLinesOfCode(at indentation: Indentation) -> [LineOfCode] {
        return indentation.apply(
            toFirstLine: "struct \(name): CreatableFromJSON { // TODO: Rename this struct",
            nestedLines:      linesOfCodeForMembers(at:),
            andLastLine: "}")
    }
    
    private func linesOfCodeForMembers(at indentation: Indentation) -> [LineOfCode] {
        return linesOfCodeForProperties(at: indentation)
            + initializer.toLinesOfCode(at: indentation)
            + failableInitializer.toLinesOfCode(at: indentation)
            + linesOfCodeForNestedStructs(at: indentation)
    }
    
    private func linesOfCodeForProperties(at indentation: Indentation) -> [LineOfCode] {
        return sortedProperties.map { property in
            let propertyCode = property.toLineOfCode()
            return indentation.apply(toLineOfCode: propertyCode)
        }
    }
    
    private var sortedProperties: [SwiftProperty] {
        return properties.sorted { (lhs, rhs) -> Bool in
            return lhs.name.compare(rhs.name) == .orderedAscending
        }
    }
    
    private func linesOfCodeForNestedStructs(at indentation: Indentation) -> [LineOfCode] {
        return nestedStructs.flatMap { $0.toLinesOfCode(at: indentation) }
    }
    
    private var sortedNestedStructs: [SwiftStruct] {
        return nestedStructs.sorted(by: { (lhs, rhs) -> Bool in
            return lhs.name.compare(rhs.name) == .orderedAscending
        })
    }
}

fileprivate extension SwiftType {
    func toSwiftCode() -> SwiftCode {
        return isOptional ? name + "?" : name
    }
}
<commit_msg>Sort nested structs by name<commit_after>//
//  swift-code-generation.swift
//  json2swift
//
//  Created by <NAME> on 10/14/16.
//  Copyright © 2016 iJoshSmith. All rights reserved.
//

import Foundation

struct SwiftCodeGenerator {
    /// This method is used when only one Swift file is being generated.
    static func generateCodeWithJSONUtilities(for swiftStruct: SwiftStruct) -> String {
        return [
            "// This file was generated by json2swift.",
            "",
            "import Foundation",
            "",
            "//",
            "// MARK: - Data Model",
            "//",
            swiftStruct.toSwiftCode(),
            "",
            "//",
            "// MARK: - JSON Utilities",
            "//",
            jsonUtilitiesTemplate,
            ""].joined(separator: "\n")
    }
    
    /// This method is used when multiple Swift files are being generated.
    static func generateCode(for swiftStruct: SwiftStruct) -> String {
        return [
            "// This file was generated by json2swift.",
            "",
            "import Foundation",
            "",
            swiftStruct.toSwiftCode(),
            ""].joined(separator: "\n")
    }
    
    /// This method is used to only create the JSON utility code once when multiple Swift files are being generated.
    static func generateJSONUtilities() -> String {
        return [
            "// This file was generated by json2swift.",
            "",
            "import Foundation",
            "",
            jsonUtilitiesTemplate,
            ""].joined(separator: "\n")
    }
}


// MARK: - Implementation

typealias SwiftCode = String
typealias LineOfCode = SwiftCode

fileprivate struct Indentation {
    private let chars: String
    private let level: Int
    private let value: String
    
    init(chars: String, level: Int = 0) {
        precondition(level >= 0)
        self.chars = chars
        self.level = level
        self.value = String(repeating: chars, count: level)
    }
    
    func apply(toLineOfCode lineOfCode: LineOfCode) -> LineOfCode {
        return value + lineOfCode
    }
    
    func apply(toFirstLine firstLine: LineOfCode,
               nestedLines generateNestedLines: (Indentation) -> [LineOfCode],
               andLastLine lastLine: LineOfCode) -> [LineOfCode] {
        let first  = apply(toLineOfCode: firstLine)
        let middle = generateNestedLines(self.increased())
        let last   = apply(toLineOfCode: lastLine)
        return [first] + middle + [last]
    }
    
    private func increased() -> Indentation {
        return Indentation(chars: chars, level: level + 1)
    }
}

fileprivate extension SwiftStruct {
    func toSwiftCode(indentedBy indentChars: String = "    ") -> SwiftCode {
        let indentation = Indentation(chars: indentChars)
        let linesOfCode = toLinesOfCode(at: indentation)
        return linesOfCode.joined(separator: "\n")
    }
    
    private func toLinesOfCode(at indentation: Indentation) -> [LineOfCode] {
        return indentation.apply(
            toFirstLine: "struct \(name): CreatableFromJSON { // TODO: Rename this struct",
            nestedLines:      linesOfCodeForMembers(at:),
            andLastLine: "}")
    }
    
    private func linesOfCodeForMembers(at indentation: Indentation) -> [LineOfCode] {
        return linesOfCodeForProperties(at: indentation)
            + initializer.toLinesOfCode(at: indentation)
            + failableInitializer.toLinesOfCode(at: indentation)
            + linesOfCodeForNestedStructs(at: indentation)
    }
    
    private func linesOfCodeForProperties(at indentation: Indentation) -> [LineOfCode] {
        return sortedProperties.map { property in
            let propertyCode = property.toLineOfCode()
            return indentation.apply(toLineOfCode: propertyCode)
        }
    }
    
    private var sortedProperties: [SwiftProperty] {
        return properties.sorted { (lhs, rhs) -> Bool in
            return lhs.name.compare(rhs.name) == .orderedAscending
        }
    }
    
    private func linesOfCodeForNestedStructs(at indentation: Indentation) -> [LineOfCode] {
        return sortedNestedStructs.flatMap { $0.toLinesOfCode(at: indentation) }
    }
    
    private var sortedNestedStructs: [SwiftStruct] {
        return nestedStructs.sorted(by: { (lhs, rhs) -> Bool in
            return lhs.name.compare(rhs.name) == .orderedAscending
        })
    }
}

fileprivate extension SwiftType {
    func toSwiftCode() -> SwiftCode {
        return isOptional ? name + "?" : name
    }
}

{'fraction_non_alphanumeric': 0.10144927536231885, 'fraction_numerical': 0.003952569169960474, 'mean_word_length': 2.1334709322325422, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 37, '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': '6873009', 'n_tokens_mistral': 2588, 'n_tokens_neox': 2501, 'n_words': 642}