     }
 }
 
+struct Property {
+    let name: String
+    let typeName: String
+
+    init(name: String, typeName: String) {
+        self.name = name
+        self.typeName = typeName
+    }
+
+    init?(structure: Structure) {
+        guard structure.kind == .varInstance,
+            let name = structure.name,
+            let typeName = structure.typeName else {
+            return nil
+        }
+
+        self.name = name
+        self.typeName = typeName
+    }
+}
+
 struct Type {
     private static var declarationKinds: [SwiftDeclarationKind] {
         return [.struct, .class, .enum, .protocol]


    let name: String
    let kind: SwiftDeclarationKind
    let fuctions: [Function]
    let inheritedTypes: [String]

    init?(structure: Structure) {

let injectables = types.filter { $0.inheritedTypes.contains("Injectable") }
let parameters = injectables
    .reduce([] as [String]) { parameters, injectable -> [String] in
        return parameters + injectable.functions.reduce([] as [String]) { parameters, function -> [String] in
            return parameters + function.parameters.reduce([] as [String]) { parameters, parameter -> [String] in
                return parameters.contains(parameter.typeName) ? parameters : parameters + [parameter.typeName]
            }
        }
    }

struct GraphError: Error {
    let message: String
}

struct Node {
    let type: Type
    let dependencies: [Node]

    init(name: String, injectables: [Type]) throws {
        guard let type = injectables.filter({ $0.name == name }).first else {
            throw GraphError(message: "Injectable type named \(name) is not found.")
        }

        let initializerParameters = Array(type.functions
            .filter { $0.isInitializer }
            .map { $0.parameters }
            .joined())

        var dependencies: [Node] = []
        for parameter in initializerParameters {
            guard let type = injectables.filter({ $0.name == parameter.typeName}).first else {
                throw GraphError(message: "Injectable type named \(name) is not found.")
            }

            let node = try Node(name: type.name, injectables: injectables)
            dependencies.append(node)
        }

        self.type = type
        self.dependencies = dependencies
    }
}

struct ModuleBuiler {
    let moduleName: String
    let nodes: [Node]
    let publicProperties: [Property]
    let privateProperties: [Property]

    init(blueprint: Type, injectables: [Type]) throws {
        let suffix = "Blueprint"
        guard blueprint.name.hasSuffix(suffix) else {
            throw GraphError(message: "Blueprint type must have suffix \(suffix).")
        }

        self.moduleName = {
            let name = blueprint.name
            return name[name.startIndex..<name.index(name.endIndex, offsetBy: -suffix.characters.count)]
        }()

        self.nodes = try blueprint.properties.map { try Node(name: $0.typeName, injectables: injectables) }

        let publicProperties = blueprint.properties
        var privateProperties = [Property]()
        func extractNode(node: Node) {
            node.dependencies.forEach(extractNode(node:))

            let resolvedTypeNames = publicProperties.map { $0.typeName } + privateProperties.map { $0.typeName }

            if !resolvedTypeNames.contains(node.type.name) {
                var name = node.type.name
                name = name.replacingCharacters(
                    in: name.startIndex..<name.index(name.startIndex, offsetBy: 1),
                    with: String(name[name.startIndex]).lowercased())

                let property = Property(name: name, typeName: node.type.name)
                privateProperties.append(property)
            }
        }

        self.nodes.forEach { extractNode(node: $0) }
        self.publicProperties = publicProperties
        self.privateProperties = privateProperties
    }
}

let blueprints = types.filter { $0.inheritedTypes.contains("ModuleBlueprint") }

for blueprint in blueprints {
    let builder = try! ModuleBuiler(blueprint: blueprint, injectables: injectables)
    print(
        "final class \(builder.moduleName): \(blueprint.name) {\n" +
        "\(builder.publicProperties.map({ "    let \($0.name): \($0.typeName)"}).joined())\n" +
        "\(builder.privateProperties.map({ "    private let \($0.name): \($0.typeName)"}).joined())\n" +
        "}"
    )
}
