<commit_before>//
//  YumeJSONError.swift
//  JsonTest
//
//  Created by Yume on 2016/10/27.
//  Copyright © 2016年 Yume. All rights reserved.
//

import Foundation

public enum JSONDecodeError: Error {
    public struct BaseInfo {
        let keyPath:String
        let currentKey:String
        let json:JSON
        var description:String {
            return [
                "\tKeypath : \"\(keyPath)\"",
                "\tKey : \"\(currentKey)\""
//                "\tjson: \(json.data ?? "nil")"
            ].joined(separator: "\n")
        }
    }
    case keyNotFound(baseInfo:BaseInfo)
    case nullValue(baseInfo:BaseInfo)
    case typeMismatch(baseInfo:BaseInfo,expectType:Any,actualType:Any,value:Any)
    case specialCase(reason:String)
    
    static public func produceError<T> (targetType:T.Type, json:JSON, key:String) -> JSONDecodeError {
        let baseInfo = BaseInfo(keyPath: json.keypath, currentKey: key, json: json)
        guard let data = json[key].data else {
            return JSONDecodeError.keyNotFound(baseInfo: baseInfo)
        }
            
        if data is NSNull {
            return JSONDecodeError.nullValue(baseInfo: baseInfo)
        }
        
        return JSONDecodeError.typeMismatch(baseInfo: baseInfo, expectType: T.self, actualType: type(of:data),value: data)
    }
}

extension JSONDecodeError:CustomStringConvertible {
    public var description: String {
        switch self {
        case .keyNotFound(let baseInfo):
            return errorMessage(messageType: "Key Not Found::", baseInfo: baseInfo,
                                expectType: nil, actualType: nil, value: nil)
        case .nullValue(let baseInfo):
            return errorMessage(messageType: "Null Value Found At:", baseInfo: baseInfo,
                                expectType: nil, actualType: nil, value: nil)
        case .typeMismatch(let baseInfo, let expectType, let actualType,let value):
            return errorMessage(messageType: "Type Mismatch:", baseInfo: baseInfo,
                                expectType: expectType, actualType: actualType, value: value)
        case .specialCase(let reason):
            return reason
        }
    }
}

fileprivate func errorMessage(messageType: String, baseInfo:JSONDecodeError.BaseInfo,
                              expectType: Any?, actualType: Any?, value: Any?) -> String {
    let baseResult:String = [
        "",
        messageType,
        baseInfo.description
    ].joined(separator: "\n")
    guard let expectType = expectType, let actualType = actualType, let value = value else {
        return baseResult
    }
    
    return [
        baseResult,
        "\tExpected Type : \(expectType)",
        "\tActual Type : \(actualType)",
        "\tActual Value : \(value)",
    ].joined(separator: "\n")
}<commit_msg>JSON Decode Error 合併參數<commit_after>//
//  YumeJSONError.swift
//  JsonTest
//
//  Created by Yume on 2016/10/27.
//  Copyright © 2016年 Yume. All rights reserved.
//

import Foundation

public enum JSONDecodeError: Error {
    public struct BaseInfo {
        let keyPath:String
        let currentKey:String
        let json:JSON
        var description:String {
            return [
                "\tKeypath : \"\(keyPath)\"",
                "\tKey : \"\(currentKey)\""
//                "\tjson: \(json.data ?? "nil")"
            ].joined(separator: "\n")
        }
    }
    
    public struct ExtraInfo {
        let expectType:Any
        let actualType:Any
        let value:Any
        var description:String {
            return [
                "\tExpected Type : \(expectType)",
                "\tActual Type : \(actualType)",
                "\tActual Value : \(value)"
            ].joined(separator: "\n")
        }
    }
    
    case keyNotFound(baseInfo:BaseInfo)
    case nullValue(baseInfo:BaseInfo)
    case typeMismatch(baseInfo:BaseInfo,extraInfo:ExtraInfo)
    case specialCase(reason:String)
    
    static public func produceError<T> (targetType:T.Type, json:JSON, key:String) -> JSONDecodeError {
        let baseInfo = BaseInfo(keyPath: json.keypath, currentKey: key, json: json)
        guard let data = json[key].data else {
            return JSONDecodeError.keyNotFound(baseInfo: baseInfo)
        }
            
        if data is NSNull {
            return JSONDecodeError.nullValue(baseInfo: baseInfo)
        }
        
        let extraInfo = ExtraInfo(expectType: T.self, actualType: type(of:data), value: data)
        return JSONDecodeError.typeMismatch(baseInfo: baseInfo, extraInfo: extraInfo)
    }
}

extension JSONDecodeError:CustomStringConvertible {
    public var description: String {
        switch self {
        case .keyNotFound(let baseInfo):
            return errorMessage(messageType: "Key Not Found::", baseInfo: baseInfo, extraInfo: nil)
        case .nullValue(let baseInfo):
            return errorMessage(messageType: "Null Value Found At:", baseInfo: baseInfo, extraInfo: nil)
        case .typeMismatch(let baseInfo, let extraInfo):
            return errorMessage(messageType: "Type Mismatch:", baseInfo: baseInfo, extraInfo: extraInfo)
        case .specialCase(let reason):
            return reason
        }
    }
    
    private func errorMessage(messageType: String, baseInfo: BaseInfo, extraInfo: ExtraInfo?) -> String {
        return [
            "",
            messageType,
            baseInfo.description,
            extraInfo?.description
        ].flatMap {$0}.joined(separator: "\n")
    }
}
{'fraction_non_alphanumeric': 0.10527272727272727, 'fraction_numerical': 0.004545454545454545, 'mean_word_length': 2.1614942528735632, 'pattern_counts': {'":': 0, '<': 5, '<?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': '6247935', 'n_tokens_mistral': 1558, 'n_tokens_neox': 1511, 'n_words': 386}