import Foundation /// A Sendable, Codable JSON value used for feature flags and request variables. package enum JSONValue: Codable, Hashable, Sendable { case null case bool(Bool) case number(Double) case string(String) case array([JSONValue]) case object([String: JSONValue]) package init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() if container.decodeNil() { self = .null } else if let value = try? container.decode(Bool.self) { self = .bool(value) } else if let value = try? container.decode(Double.self) { self = .number(value) } else if let value = try? container.decode(String.self) { self = .string(value) } else if let value = try? container.decode([JSONValue].self) { self = .array(value) } else { self = .object(try container.decode([String: JSONValue].self)) } } package func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer() switch self { case .null: try container.encodeNil() case .bool(let value): try container.encode(value) case .number(let value): if value.rounded() == value, abs(value) < 1e15 { try container.encode(Int64(value)) } else { try container.encode(value) } case .string(let value): try container.encode(value) case .array(let value): try container.encode(value) case .object(let value): try container.encode(value) } } package subscript(key: String) -> JSONValue? { if case .object(let object) = self { return object[key] } return nil } package func encodedString() -> String { let encoder = JSONEncoder() encoder.outputFormatting = [.sortedKeys, .withoutEscapingSlashes] return (try? encoder.encode(self)).map { String(decoding: $0, as: UTF8.self) } ?? "{}" } } extension JSONValue: ExpressibleByStringLiteral, ExpressibleByBooleanLiteral, ExpressibleByIntegerLiteral, ExpressibleByDictionaryLiteral, ExpressibleByArrayLiteral, ExpressibleByNilLiteral { package init(stringLiteral value: String) { self = .string(value) } package init(booleanLiteral value: Bool) { self = .bool(value) } package init(integerLiteral value: Int) { self = .number(Double(value)) } package init(dictionaryLiteral elements: (String, JSONValue)...) { self = .object(Dictionary(elements, uniquingKeysWith: { $1 })) } package init(arrayLiteral elements: JSONValue...) { self = .array(elements) } package init(nilLiteral: ()) { self = .null } }