 extension JSON {
 
     public var description: String {
-        guard let jsonString = stringify() else {
+        guard let string = stringify() else {
             return "<INVALID JSON>"
         }
-        return jsonString
+        return string
     }
 
     private func prettyPrint(_ indent: String, _ level: Int) -> String {


    public var boolValue: Bool {
        switch self {
        case .jsonBool(let bool):
            return bool
        case .jsonInvalid:
            return false
        default:
            return true


import Foundation

enum JSONError: ErrorProtocol {
    case parseError(String)
}

public enum JSON : Equatable, CustomStringConvertible {
    
    case string(String)
    case number(Double)
    case object(Dictionary<String, JSON>)
    case array(Array<JSON>)
    case bool(Bool)
    case null
    case invalid
    
    init(_ value: Bool?) {
        guard let bool = value else {
            self = .invalid
            return
        }
        self = .bool(bool)
    }
    
    init(_ value: Double?) {
        guard let number = value else {
            self = .invalid
            return
        }
        self = .number(number)
    }
    
    init(_ value: Int?) {
        guard let number = value else {
            self = .invalid
            return
        }
        self = .number(Double(number))
    }
    
    init(_ value: String?) {
        guard let string = value else {
            self = .invalid
            return
        }
        self = .string(string)
    }
    
    init(_ value: [JSON]?) {
        guard let array = value else {
            self = .invalid
            return
        }
        self = .array(array)
    }
    
    init(_ value: [String: JSON]?) {
        guard let dict = value else {
            self = .invalid
            return
        }
        self = .object(dict)
    }
    
    init(_ rawValue: AnyObject?) {
        guard let value = rawValue else {
            self = .invalid
            return
        }

        switch value {
        case let data as Data:
            do {
                let object = try JSONSerialization.jsonObject(with: data, options: [])
                self = JSON(object)
            } catch {
                self = .invalid
            }
            
        case let array as NSArray:
            let newArray = array.map { JSON($0) }
            self = .array(newArray)
            
        case let dict as [String: AnyObject]:
            var newDict = [String: JSON]()
            for (key, value) in dict {
                newDict[key] = JSON(value)
            }
            self = .object(newDict)
            
        case let string as String:
            self = .string(string)
            
        case let number as NSNumber:
            if number.isBool {
                self = .bool(number.boolValue)
            } else {
                self = .number(number.doubleValue)
            }
            
        case _ as NSNull:
            self = .null
            
        default:
            assert(true, "This location should never be reached")
            self = .invalid
        }

    }

    public var string : String? {
        guard case .string(let value) = self else {
            return nil
        }
        return value
    }

    public var integer : Int? {
        guard case .number(let value) = self else {
            return nil
        }
         return Int(value)
    }

    public var double : Double? {
        guard case .number(let value) = self else {
            return nil
        }
        return value
    }

    public var object : [String: JSON]? {
        guard case .object(let value) = self else {
            return nil
        }
        return value
    }

    public var array : [JSON]? {
        guard case .array(let value) = self else {
            return nil
        }
        return value
    }

    public var bool : Bool? {
        guard case .bool(let value) = self else {
            return nil
        }
        return value
    }

    public subscript(key: String) -> JSON {
        guard case .object(let dict) = self, let value = dict[key] else {
            return .invalid
        }
        return value
    }

    public subscript(index: Int) -> JSON {
        guard case .array(let array) = self where array.count > index else {
            return .invalid
        }
        return array[index]
    }

    static func parse(jsonData: Data) throws -> JSON {
        do {
            let object = try JSONSerialization.jsonObject(with: jsonData, options: .mutableContainers)
            return JSON(object)
        } catch {
            throw JSONError.parseError("\(error)")
        }
    }

    static func parse(string : String) throws -> JSON {
        do {
            guard let data = string.data(using: .utf8, allowLossyConversion: false) else {
                throw JSONError.parseError("Cannot parse invalid string")
            }
            return try parse(jsonData: data)
