[
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: robb\n"
  },
  {
    "path": ".github/workflows/swift_linux.yml",
    "content": "name: Swift Linux\n\non: [push]\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n\n    steps:\n    - uses: actions/checkout@v1\n    - name: Build\n      run: swift build -v\n    - name: Run tests\n      run: swift test --enable-test-discovery -v\n"
  },
  {
    "path": ".github/workflows/swift_macos.yml",
    "content": "name: Swift macOS\n\non: [push]\n\njobs:\n  build:\n    runs-on: macOS-latest\n\n    steps:\n    - name: Select Xcode\n      run: sudo xcode-select -switch /Applications/Xcode_12.3.app\n    - uses: actions/checkout@v1\n    - name: Build\n      run: swift build -v\n    - name: Run tests\n      run: swift test --enable-test-discovery -v\n"
  },
  {
    "path": ".gitignore",
    "content": ".DS_Store\n/.build\n/Packages\n/*.xcodeproj\nxcuserdata/\n"
  },
  {
    "path": "LICENSE.md",
    "content": "MIT License\n\nCopyright (c) 2020 Robert Böhnke\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "Package.swift",
    "content": "// swift-tools-version:5.2\n// The swift-tools-version declares the minimum version of Swift required to build this package.\n\nimport PackageDescription\n\nlet package = Package(\n    name: \"RBBJSON\",\n    platforms: [\n        .iOS(.v13),\n        .macOS(.v10_15)\n    ],\n    products: [\n        // Products define the executables and libraries produced by a package, and make them visible to other packages.\n        .library(\n            name: \"RBBJSON\",\n            targets: [\"RBBJSON\"]),\n    ],\n    dependencies: [\n        // Dependencies declare other packages that this package depends on.\n        // .package(url: /* package url */, from: \"1.0.0\"),\n    ],\n    targets: [\n        // Targets are the basic building blocks of a package. A target can define a module or a test suite.\n        // Targets can depend on other targets in this package, and on products in packages which this package depends on.\n        .target(\n            name: \"RBBJSON\",\n            dependencies: []),\n        .testTarget(\n            name: \"RBBJSONTests\",\n            dependencies: [\"RBBJSON\"]),\n    ]\n)\n"
  },
  {
    "path": "README.md",
    "content": "# RBBJSON\n\n<p align=\"left\">\n    <img src=\"https://img.shields.io/badge/Swift_Version-5.2-orange.svg?style=flat&logo=Swift\" alt=\"Swift Version: 5.2\" />\n    <a href=\"https://swift.org/package-manager\">\n        <img src=\"https://img.shields.io/badge/SwiftPM-Compatible-darkgreen.svg?style=flat\" alt=\"Swift Package Manager\" />\n    </a>\n      <img src=\"https://img.shields.io/badge/Platforms-macOS,%20iOS,%20Linux-darkgreen.svg?style=flat\" alt=\"Swift Package Manager\" />\n    <a href=\"https://twitter.com/DLX\">\n        <img src=\"https://img.shields.io/badge/Twitter-@DLX-blue.svg?style=flat&logo=Twitter\" alt=\"Twitter: @DLX\" />\n    </a>\n</p>\n\nRBBJSON enables flexible JSON traversal at runtime and [JSONPath]-like querying for rapid prototyping.\n\nUse `JSONDecoder` to create an `RBBJSON` struct, then traverse it using [dynamic member lookup][dml]:\n\n```swift\nlet json = try JSONDecoder().decode(RBBJSON.self, from: data)\n\njson.firstName         // RBBJSON.string(\"John\")\njson.lastName          // RBBJSON.string(\"Appleseed\")\njson.age               // RBBJSON.number(26)\njson.invalidKey        // RBBJSON.null\njson.phoneNumbers[0]   // RBBJSON.string(\"+14086065775\")\n```\n\nIf you want to access a value that coincides with a Swift-defined property, use a `String` subscript instead:\n\n```swift\njson.office.map     // Error: Maps to Sequence.map\njson.office[\"map\"]  // RBBJSON.string(\"https://maps.apple.com/?q=IL1\")\n```\n\nTo unbox a JSON value, use one of the failable initializers:\n\n```swift\nString(json.firstName) // \"John\"\nString(json.lastName)  // \"Appleseed\"\nString(json.age)       // nil\n\nInt(json.age)          // 26\nDouble(json.age)       // 26.0\n```\n\nYou can also make use of a [JSONPath]-inspired Query syntax to find nested data inside a JSON structure.\n\nFor example, given:\n\n```json\n{ \n  \"store\": {\n    \"book\": [ \n      { \n        \"category\": \"reference\",\n        \"author\": \"Nigel Rees\",\n        \"title\": \"Sayings of the Century\",\n        \"price\": 8.95\n      },\n      { \n        \"category\": \"fiction\",\n        \"author\": \"Evelyn Waugh\",\n        \"title\": \"Sword of Honour\",\n        \"price\": 12.99\n      },\n      { \n        \"category\": \"fiction\",\n        \"author\": \"Herman Melville\",\n        \"title\": \"Moby Dick\",\n        \"isbn\": \"0-553-21311-3\",\n        \"price\": 8.99\n      },\n      { \n        \"category\": \"fiction\",\n        \"author\": \"J. R. R. Tolkien\",\n        \"title\": \"The Lord of the Rings\",\n        \"isbn\": \"0-395-19395-8\",\n        \"price\": 22.99\n      }\n    ],\n    \"bicycle\": {\n      \"color\": \"red\",\n      \"price\": 19.95\n    }\n  }\n}\n```\n\n|JSONPath|RBBJSON|Result|\n|-|-|-|\n|`$.store.book[*].author`|`json.store.book[any: .child].author`|[The authors of all books in the store.](/Tests/RBBJSONTests/READMETests.swift#L46-L51)|\n|`$..author`|`json[any: .descendantOrSelf].author`|[All authors.](/Tests/RBBJSONTests/READMETests.swift#L56-L61)|\n|`$.store.*`|`json.store[any: .child]`|[All things in the store, a list of books an a red bycicle.](/Tests/RBBJSONTests/READMETests.swift#L66-L99)|\n|`$.store..price`|`json.store[any: .descendantOrSelf].price`|[All prices in the store.](/Tests/RBBJSONTests/READMETests.swift#L104-L110)|\n|`$..book[2]`|`json[any: .descendantOrSelf].book[2]`|[The second book.](/Tests/RBBJSONTests/READMETests.swift#L115-L123)|\n|`$..book[-2]`|`json[any: .descendantOrSelf].book[-2]`|[The second-to-last book.](/Tests/RBBJSONTests/READMETests.swift#L128-L136)|\n|`$..book[0,1]`, `$..book[:2]`|`json[any: .descendantOrSelf].book[0, 1])`, `json[any: .descendantOrSelf].book[0...1])`, `json[any: .descendantOrSelf].book[0..<2])`|[The first two books.](/Tests/RBBJSONTests/READMETests.swift#L141-L154)|\n|`$..book[?(@.isbn)]`|`json[any: .descendantOrSelf].book[has: \\.isbn]`|[All books with an ISBN number.](/Tests/RBBJSONTests/READMETests.swift#L159-L174)|\n|`$..book[?(@.price<10)]`|`json.store.book[matches: { $0.price <= 10 }]`|[All books cheaper than `10`.](/Tests/RBBJSONTests/READMETests.swift#L179-L193)|\n|`$.store[\"book\", \"bicycle\"]..[\"price\", \"author\"]`|`json.store[\"book\", \"bicycle\"][any: .descendantOrSelf][\"price\", \"author\"]`|[The author (where available) and price of every book or bicycle.](/Tests/RBBJSONTests/READMETests.swift#L203-L223)|\n\nOnce you query a JSON value using one of the higher order selectors, the resulting type of the expression will be a lazy `RBBJSONQuery`:\n\n```swift\njson.store.book[0][\"title\"]     // RBBJSON.string(\"Sayings of the Century\")\njson.store.book[0, 1][\"title\"]  // some RBBJSONQuery\n```\n\nBecause `RBBJSONQuery` conforms to `Sequence`, you can initialize an `Array` with it to obtain the results or use e.g. `compactMap`:\n\n```swift\nString(json.store.book[0].title)                    // \"Sayings of the Century\"\njson.store.book[0, 1].title.compactMap(String.init) // [\"Sayings of the Century\", \"Sword of Honour\"]\n\nString(json.store.book[0][\"invalid Property\"])                    // nil\njson.store.book[0, 1][\"invalid Property\"].compactMap(String.init) // []\n```\n\n---\n\n\n\n[jsonpath]: https://goessner.net/articles/JsonPath/\n[dml]: https://oleb.net/blog/2018/06/dynamic-member-lookup/\n"
  },
  {
    "path": "Sources/RBBJSON/RBBJSON+Boolean.swift",
    "content": "import Foundation\n\npublic extension Bool {\n    init?(_ json: RBBJSON, lenient: Bool = false) {\n        switch (json, lenient) {\n        case (.bool(let value), _):\n            self = value\n        case (.string(\"true\"), true):\n            self = true\n        case (.string(\"false\"), true):\n            self = false\n        case (.number(let value), true):\n            self = value != 0\n        default:\n            return nil\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/RBBJSON/RBBJSON+Comparable.swift",
    "content": "import Foundation\n\nextension RBBJSON: Comparable {\n    static func sortKey(value: RBBJSON) -> Int {\n        switch value {\n        case .object:\n            return 1\n        case .array:\n            return 2\n        case .number:\n            return 3\n        case .string:\n            return 4\n        case .bool:\n            return 5\n        case .null:\n            return 6\n        }\n    }\n\n    /// Compares two `RBBJSON` values against each other.\n    ///\n    /// Note that this is not equivalent to JavaScript's comparison of\n    /// heterogenous values.\n    public static func < (lhs: RBBJSON, rhs: RBBJSON) -> Bool {\n        switch (lhs, rhs) {\n        case (.object(let l), .object(let r)):\n            return l.count < r.count\n        case (.array(let l), .array(let r)):\n            return l.count < r.count\n        case (.string(let l), .string(let r)):\n            return l < r\n        case (.number(let l), .number(let r)):\n            return l < r\n        case (.bool(let l), .bool(let r)):\n            return (l ? 1 : 0) < (r ? 1 : 0)\n        case (.null, .null):\n            return false\n        default:\n            return sortKey(value: lhs) < sortKey(value: rhs)\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/RBBJSON/RBBJSON+Date.swift",
    "content": "import Foundation\n\n@available(macOS 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)\npublic extension Date {\n    enum JSONDateStringDecodingStrategy: Hashable {\n        fileprivate static let isoParser = ISO8601DateFormatter()\n\n        case iso8601\n        case formatted(DateFormatter)\n    }\n\n    enum JSONDateNumberDecodingStrategy {\n        case secondsSince1970\n        case millisecondsSince1970\n    }\n\n    init?(_ json: RBBJSON, stringDecodingStrategoy: JSONDateStringDecodingStrategy = .iso8601, numberDecodingStrategoy: JSONDateNumberDecodingStrategy = .secondsSince1970) {\n        switch (json, stringDecodingStrategoy, numberDecodingStrategoy) {\n        case let (.number(value), _, .secondsSince1970):\n            self = Date(timeIntervalSince1970: value)\n        case let (.number(value), _, .millisecondsSince1970):\n            self = Date(timeIntervalSince1970: value / 1000)\n        case let (.string(value), .iso8601, _):\n            if let date = JSONDateStringDecodingStrategy.isoParser.date(from: value) {\n                self = date\n            } else {\n                return nil\n            }\n        case let (.string(value), .formatted(formatter), _):\n            if let date = formatter.date(from: value) {\n                self = date\n            } else {\n                return nil\n            }\n        default:\n            return nil\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/RBBJSON/RBBJSON+Numbers.swift",
    "content": "import Foundation\n#if canImport(CoreGraphics)\nimport CoreGraphics\n\npublic extension CGFloat {\n    init?(_ json: RBBJSON, lenient: Bool = false) {\n        switch (json, lenient) {\n        case (.number(let value), _):\n            self = Self(value)\n        case (.string(let string), true):\n            guard let double = Double(string) else {\n                return nil\n            }\n\n            self.init(double)\n        default:\n            return nil\n        }\n    }\n}\n#endif\n\npublic extension Double {\n    init?(_ json: RBBJSON, lenient: Bool = false) {\n        switch (json, lenient) {\n        case (.number(let value), _):\n            self = Self(value)\n        case (.string(let string), true):\n            self.init(string)\n        default:\n            return nil\n        }\n    }\n}\n\npublic extension FixedWidthInteger {\n    init?(_ json: RBBJSON, lenient: Bool = false) {\n        switch (json, lenient) {\n        case (.number(let value), _):\n            self = Self(value)\n        case (.string(let string), true):\n            if let value = Self(string) {\n                self = value\n            } else if let double = Double(json, lenient: true) {\n                self.init(double)\n            } else {\n                return nil\n            }\n        default:\n            return nil\n        }\n\n    }\n}\n\npublic extension Float {\n    init?(_ json: RBBJSON, lenient: Bool = false) {\n        switch (json, lenient) {\n        case (.number(let value), _):\n            self = Self(value)\n        case (.string(let string), true):\n            self.init(string)\n        default:\n            return nil\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/RBBJSON/RBBJSON+PlaygroundSupport.swift",
    "content": "import Foundation\n\nextension RBBJSON: CustomPlaygroundDisplayConvertible {\n    public var playgroundDescription: Any {\n        switch self {\n        case .object(let object):\n            return object.mapValues(\\.playgroundDescription)\n        case .array(let values):\n            return values.map(\\.playgroundDescription)\n        case .string(let value):\n            return value\n        case .number(let value):\n            return value\n        case .bool(let value):\n            return value\n        case .null:\n            return Optional<String>.none as Any\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/RBBJSON/RBBJSON+String.swift",
    "content": "import Foundation\n\npublic extension String {\n    init?(_ json: RBBJSON) {\n        if case .string(let value) = json {\n            self = value\n        } else {\n            return nil\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/RBBJSON/RBBJSON.swift",
    "content": "import Foundation\n\nfileprivate struct JSONCodingKeys: CodingKey {\n    internal var stringValue: String\n\n    internal init?(stringValue: String) {\n        self.stringValue = stringValue\n    }\n\n    internal var intValue: Int?\n\n    internal init?(intValue: Int) {\n        self.init(stringValue: \"\\(intValue)\")\n        self.intValue = intValue\n    }\n}\n\n@dynamicMemberLookup\npublic enum RBBJSON: Hashable, Codable {\n    case object([String: RBBJSON])\n    case array([RBBJSON])\n    case string(String)\n    case number(Double)\n    case bool(Bool)\n    case null\n\n    public init(from decoder: Decoder) throws {\n        if let container = try? decoder.container(keyedBy: JSONCodingKeys.self) {\n            self = try RBBJSON(container: container)\n        } else if var container = try? decoder.unkeyedContainer() {\n            self = try RBBJSON(container: &container)\n        } else if let container = try? decoder.singleValueContainer() {\n            if let bool = try? container.decode(Bool.self) {\n                self = .bool(bool)\n            } else if let number = try? container.decode(Double.self) {\n                self = .number(number)\n            } else if let string = try? container.decode(String.self) {\n                self = .string(string)\n            } else if container.decodeNil() {\n                self = .null\n            } else {\n                throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: \"\"))\n            }\n        }\n        else {\n            throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: \"\"))\n        }\n    }\n\n    private init(container: KeyedDecodingContainer<JSONCodingKeys>) throws {\n        let values = try container.allKeys.map { codingKey -> RBBJSON in\n            try container.decode(RBBJSON.self, forKey: codingKey)\n        }\n\n        let zipped = zip(container.allKeys.map(\\.stringValue), values)\n\n        self = .object(Dictionary(zipped) { a, _ in a })\n    }\n\n    private init(container: inout UnkeyedDecodingContainer) throws {\n        var values: [RBBJSON] = []\n\n        while !container.isAtEnd {\n            values.append(try container.decode(RBBJSON.self))\n        }\n\n        self = .array(values)\n    }\n\n    public func encode(to encoder: Encoder) throws {\n        switch self {\n        case .object(let object):\n            var container = encoder.container(keyedBy: JSONCodingKeys.self)\n\n            for (key, value) in object {\n                let codingKey = JSONCodingKeys(stringValue: key)!\n\n                try container.encode(value, forKey: codingKey)\n            }\n        case .array(let array):\n            var container = encoder.unkeyedContainer()\n\n            for value in array {\n                try container.encode(value)\n            }\n        case .string(let string):\n            var container = encoder.singleValueContainer()\n\n            try container.encode(string)\n        case .number(let number):\n            var container = encoder.singleValueContainer()\n\n            try container.encode(number)\n        case .bool(let bool):\n            var container = encoder.singleValueContainer()\n\n            try container.encode(bool)\n        case .null:\n            var container = encoder.singleValueContainer()\n\n            try container.encodeNil()\n        }\n    }\n\n    public subscript(index: Int) -> RBBJSON {\n        guard case .array(let array) = self else { return .null }\n\n        return array[wrapping: index] ?? .null\n    }\n\n    public subscript(key: String) -> RBBJSON {\n        guard case .object(let object) = self else { return .null }\n\n        return object[key] ?? .null\n    }\n\n    public subscript(dynamicMember member: String) -> RBBJSON {\n        self[member]\n    }\n\n    public static func keys(_ json: RBBJSON) -> [String] {\n        switch json {\n        case .object(let object):\n            return Array(object.keys).sortedIfDebug\n        default:\n            return []\n        }\n    }\n\n    public static func values(_ json: RBBJSON) -> [RBBJSON] {\n        switch json {\n        case .object(let object):\n            return Array(object.values).sortedIfDebug\n        case .array(let array):\n            return array\n        default:\n            return []\n        }\n    }\n}\n\nextension RBBJSON: CustomDebugStringConvertible {\n    public var debugDescription: String {\n        switch self {\n        case .object(let object):\n            return object.debugDescription\n        case .array(let array):\n            return array.debugDescription\n        case .string(let string):\n            return string.debugDescription\n        case .number(let number):\n            return number.debugDescription\n        case .bool(let bool):\n            return bool ? \"true\" : \"false\"\n        case .null:\n            return \"null\"\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/RBBJSON/RBBJSONQuery.swift",
    "content": "import Foundation\n\n@dynamicMemberLookup\npublic protocol RBBJSONQuery: Sequence, CustomPlaygroundDisplayConvertible where Element == RBBJSON {\n\n}\n\nextension RBBJSONQuery {\n    var playgroundDescription: Any {\n        map(\\.playgroundDescription)\n    }\n}\n\npublic extension RBBJSON {\n    enum Axis {\n        /// Matches any immediate child of a JSON object or array.\n        case child\n\n        /// Matches any immediate or transitive child of a JSON object or array as\n        /// well as itself.\n        case descendantOrSelf\n    }\n\n    /// Matches multiple indices on a JSON array. Negative indices can be\n    /// used to index from the end.\n    subscript(indices: Int...) -> some RBBJSONQuery {\n        IndicesSequence(base: CollectionOfOne(self), indices: indices)\n    }\n\n    /// Matches a range of indices on a JSON array. Negative indices are not\n    /// allowed.\n    subscript(range: Range<Int>) -> some RBBJSONQuery {\n        RangeSequence(range: range, base: CollectionOfOne(self))\n    }\n\n    /// Matches a range of indices on a JSON array. Negative indices are not\n    /// allowed.\n    subscript(range: ClosedRange<Int>) -> some RBBJSONQuery {\n        RangeSequence(range: range.lowerBound ..< range.upperBound + 1, base: CollectionOfOne(self))\n    }\n\n    /// Matches values on a JSON object or array that the given `predicate`\n    /// returns `true` for.\n    subscript(matches predicate: @escaping (RBBJSON) -> Bool) -> some RBBJSONQuery {\n        PredicateSequence(predicate: predicate, base: CollectionOfOne(self))\n    }\n\n    /// Matches values on a JSON object or array that the given `keyPath`\n    /// returns anything but `null` for, this includes values such as `0`,\n    /// `false` or `\"\"` that Javascript would consider falsy.\n    subscript(has keyPath: KeyPath<RBBJSON, RBBJSON>) -> some RBBJSONQuery {\n        self[matches: { $0[keyPath: keyPath] != .null }]\n    }\n\n    subscript(any axis: Axis) -> some RBBJSONQuery {\n        AxisSequence(axis: axis, base: CollectionOfOne(self))\n    }\n\n    subscript(keys: String...) -> some RBBJSONQuery {\n        KeysSequence(keys: keys, base: CollectionOfOne(self))\n    }\n}\n\nextension RBBJSON {\n    @dynamicMemberLookup\n    struct KeySequence<Base>: RBBJSONQuery where Base: Sequence, Base.Element == RBBJSON {\n        var key: String\n\n        var base: Base\n\n        public func makeIterator() -> AnyIterator<RBBJSON> {\n            let underlying = base.lazy.map { $0[key] }\n                .filter { $0 != .null }\n                .makeIterator()\n\n            return AnyIterator(underlying)\n        }\n    }\n\n    @dynamicMemberLookup\n    struct KeysSequence<Base>: RBBJSONQuery where Base: Sequence, Base.Element == RBBJSON {\n        var keys: [String]\n\n        var base: Base\n\n        public func makeIterator() -> AnyIterator<RBBJSON> {\n            let underlying = base\n                .lazy\n                .compactMap { object -> RBBJSON? in\n                    let keysAndValues: [(String, RBBJSON)] = keys.compactMap { key in\n                        let value = object[key]\n\n                        guard value != .null else { return nil }\n\n                        return (key, value)\n                    }\n\n                    if !keysAndValues.isEmpty {\n                        return .object(Dictionary(keysAndValues) { a, _ in a })\n                    } else {\n                        return nil\n                    }\n                }\n                .makeIterator()\n\n            return AnyIterator(underlying)\n        }\n    }\n\n    @dynamicMemberLookup\n    struct AnyChildSequence<Base>: RBBJSONQuery where Base: Sequence, Base.Element == RBBJSON {\n        var base: Base\n\n        public func makeIterator() -> AnyIterator<RBBJSON> {\n            let underlying = base.lazy.flatMap {\n                RBBJSON.values($0)\n            }\n            .makeIterator()\n\n            return AnyIterator(underlying)\n        }\n    }\n\n    @dynamicMemberLookup\n    struct IndicesSequence<Base>: RBBJSONQuery where Base: Sequence, Base.Element == RBBJSON {\n        var base: Base\n\n        var indices: [Int]\n\n        public func makeIterator() -> AnyIterator<RBBJSON> {\n            let underlying = base.lazy.flatMap { object -> [RBBJSON] in\n                let results = indices.map { object[$0] }.filter { $0 != .null }\n\n                if results.isEmpty {\n                    return []\n                } else {\n                    return results\n                }\n            }\n            .makeIterator()\n\n            return AnyIterator(underlying)\n        }\n    }\n\n    @dynamicMemberLookup\n    struct RangeSequence<Base>: RBBJSONQuery where Base: Sequence, Base.Element == RBBJSON {\n        var range: Range<Int>\n\n        var base: Base\n\n        public func makeIterator() -> AnyIterator<RBBJSON> {\n            let underlying = base.lazy.flatMap { object -> AnySequence<RBBJSON> in\n                switch object {\n                case let .array(array):\n                    let clampedRange = range.clamped(to: array.indices)\n\n                    return AnySequence(array[clampedRange])\n                default:\n                    return AnySequence(EmptyCollection())\n                }\n            }\n            .makeIterator()\n\n            return AnyIterator(underlying)\n        }\n    }\n\n    @dynamicMemberLookup\n    struct PredicateSequence<Base>: RBBJSONQuery where Base: Sequence, Base.Element == RBBJSON {\n        var predicate: (RBBJSON) -> Bool\n\n        var base: Base\n\n        public func makeIterator() -> AnyIterator<RBBJSON> {\n            let underlying = base.lazy.flatMap { object -> AnySequence<RBBJSON> in\n                switch object {\n                case let .array(array):\n                    return AnySequence(array.lazy.filter(predicate))\n                case .object where predicate(object):\n                    return AnySequence(CollectionOfOne(object))\n                default:\n                    return AnySequence(EmptyCollection())\n                }\n            }\n            .makeIterator()\n\n            return AnyIterator(underlying)\n        }\n    }\n\n    @dynamicMemberLookup\n    struct AxisSequence<Base>: RBBJSONQuery where Base: Sequence, Base.Element == RBBJSON {\n        var axis: Axis\n\n        var base: Base\n\n        public func makeIterator() -> AnyIterator<RBBJSON> {\n            switch axis {\n            case .child:\n                return AnyChildSequence(base: base).makeIterator()\n            case .descendantOrSelf:\n                let underlying = base.lazy.flatMap {\n                    RecursiveDescentSequence(json: $0)\n                }\n                .makeIterator()\n\n                return AnyIterator(underlying)\n            }\n        }\n    }\n\n    struct RecursiveDescentSequence: RBBJSONQuery {\n        var json: RBBJSON\n\n        struct Iterator: IteratorProtocol {\n            typealias Element = RBBJSON\n\n            var stack: [RBBJSON]\n\n            mutating func next() -> RBBJSON? {\n                while !stack.isEmpty {\n                    let json = stack.removeLast()\n\n                    switch json {\n                    case .null, .bool, .string, .number:\n                        continue\n\n                    case .array(let array):\n                        stack.append(contentsOf: array.reversed())\n                        return json\n\n                    case .object(let object):\n                        #if DEBUG\n                        stack.append(contentsOf: Array(object.values).sortedIfDebug.reversed())\n                        #else\n                        stack.append(contentsOf: object.values)\n                        #endif\n                        return json\n                    }\n                }\n\n                return nil\n            }\n        }\n\n        func makeIterator() -> Iterator {\n            Iterator(stack: [json])\n        }\n    }\n}\n\npublic extension RBBJSONQuery {\n    /// Matches a particular index on a JSON array. Negative indices can be\n    /// used to index from the end.\n    subscript(index: Int) -> some RBBJSONQuery {\n        RBBJSON.IndicesSequence(base: self, indices: [index])\n    }\n\n    /// Matches multiple indices on a JSON array. Negative indices can be\n    /// used to index from the end.\n    subscript(indices: Int...) -> some RBBJSONQuery {\n        RBBJSON.IndicesSequence(base: self, indices: indices)\n    }\n\n    /// Matches a particular key on a JSON object.\n    subscript(key: String) -> some RBBJSONQuery {\n        RBBJSON.KeySequence(key: key, base: self)\n    }\n\n    subscript(keys: String...) -> some RBBJSONQuery {\n        RBBJSON.KeysSequence(keys: keys, base: self)\n    }\n\n    /// Matches a particular key on a JSON object.\n    subscript(dynamicMember dynamicMember: String) -> some RBBJSONQuery {\n        RBBJSON.KeySequence(key: dynamicMember, base: self)\n    }\n\n    /// Matches values on a JSON object or array that the given `keyPath`\n    /// returns anything but `null` for, this includes values such as `0`,\n    /// `false` or `\"\"` that Javascript would consider falsy.\n    subscript(has keyPath: KeyPath<RBBJSON, RBBJSON>) -> some RBBJSONQuery {\n        RBBJSON.PredicateSequence(predicate: { $0[keyPath: keyPath] != .null }, base: self)\n    }\n\n    /// Matches a range of indices on a JSON array. Negative indices are not\n    /// allowed.\n    subscript(range: Range<Int>) -> some RBBJSONQuery {\n        RBBJSON.RangeSequence(range: range, base: self)\n    }\n\n    /// Matches a range of indices on a JSON array. Negative indices are not\n    /// allowed.\n    subscript(range: ClosedRange<Int>) -> some RBBJSONQuery {\n        RBBJSON.RangeSequence(range: range.lowerBound ..< range.upperBound + 1, base: self)\n    }\n\n    subscript(any axis: RBBJSON.Axis) -> some RBBJSONQuery {\n        RBBJSON.AxisSequence(axis: axis, base: self)\n    }\n\n    /// Matches values on a JSON object or array that the given `predicate`\n    /// returns `true` for.\n    subscript(matches predicate: @escaping (RBBJSON) -> Bool) -> some RBBJSONQuery {\n        RBBJSON.PredicateSequence(predicate: predicate, base: self)\n    }\n}\n\ninternal extension Array where Element == RBBJSON {\n    subscript(wrapping index: Int) -> Element? {\n        if index < 0 {\n            return self[safe: index + count]\n        } else {\n            return self[safe: index]\n        }\n    }\n\n    subscript(safe index: Int) -> Element? {\n        indices.contains(index) ? self[index] : nil\n    }\n}\n\ninternal extension Sequence where Element: Comparable {\n    #if DEBUG\n    var sortedIfDebug: [Element] {\n        sorted()\n    }\n    #else\n    var sortedIfDebug: Self {\n        self\n    }\n    #endif\n}\n"
  },
  {
    "path": "Tests/LinuxMain.swift",
    "content": "fatalError(\"Run the tests with `swift test --enable-test-discovery`.\")\n"
  },
  {
    "path": "Tests/RBBJSONTests/BooleanTests.swift",
    "content": "import XCTest\n\nimport RBBJSON\n\n@available(iOS 10.0, *)\nfinal class BoolTests: XCTestCase {\n    func testBooleanConversion() {\n        XCTAssertEqual(Bool(\"foo\"   as RBBJSON), nil)\n        XCTAssertEqual(Bool(\"\"      as RBBJSON), nil)\n        XCTAssertEqual(Bool(\"false\" as RBBJSON), nil)\n        XCTAssertEqual(Bool(\"true\"  as RBBJSON), nil)\n        XCTAssertEqual(Bool(0       as RBBJSON), nil)\n        XCTAssertEqual(Bool(1       as RBBJSON), nil)\n        XCTAssertEqual(Bool(3       as RBBJSON), nil)\n        XCTAssertEqual(Bool(true    as RBBJSON), true)\n        XCTAssertEqual(Bool(false   as RBBJSON), false)\n\n        XCTAssertEqual(Bool(\"foo\"   as RBBJSON, lenient: true), nil)\n        XCTAssertEqual(Bool(\"\"      as RBBJSON, lenient: true), nil)\n        XCTAssertEqual(Bool(\"false\" as RBBJSON, lenient: true), false)\n        XCTAssertEqual(Bool(\"true\"  as RBBJSON, lenient: true), true)\n        XCTAssertEqual(Bool(0       as RBBJSON, lenient: true), false)\n        XCTAssertEqual(Bool(1       as RBBJSON, lenient: true), true)\n        XCTAssertEqual(Bool(3       as RBBJSON, lenient: true), true)\n        XCTAssertEqual(Bool(true    as RBBJSON, lenient: true), true)\n        XCTAssertEqual(Bool(false   as RBBJSON, lenient: true), false)\n    }\n}\n"
  },
  {
    "path": "Tests/RBBJSONTests/ComparisonTests.swift",
    "content": "import XCTest\n\nimport RBBJSON\n\nfinal class ComparisonTests: XCTestCase {\n    func testHeterogenousSorting() {\n        let json = [\n            false,\n            \"c\",\n            nil,\n            3, 123, -2, 0,\n            \"b\",\n            [ 1, 2, 3 ],\n            [ \"one\": 1, \"zero\": 0 ],\n            \"a\",\n            true\n        ] as [RBBJSON]\n\n        XCTAssertEqual(json.sorted(), [\n            [ \"one\": 1, \"zero\": 0 ],\n            [ 1, 2, 3 ],\n            -2,\n            0,\n            3,\n            123,\n            \"a\", \"b\", \"c\",\n            false,\n            true,\n            nil,\n        ])\n    }\n}\n"
  },
  {
    "path": "Tests/RBBJSONTests/DateTests.swift",
    "content": "import XCTest\n\nimport RBBJSON\n\n@available(iOS 10.0, *)\nfinal class DateTests: XCTestCase {\n    func testDateConversion() {\n        XCTAssertEqual(Date(\"foo\" as RBBJSON), nil)\n\n        XCTAssertEqual(Date(1604942100 as RBBJSON), Date(timeIntervalSince1970: 1604942100))\n        XCTAssertEqual(Date(1604942100000 as RBBJSON, numberDecodingStrategoy: .millisecondsSince1970), Date(timeIntervalSince1970: 1604942100))\n\n        let formatter = DateFormatter()\n        formatter.locale = Locale(identifier: \"en_US_POSIX\")\n        formatter.dateFormat = \"E, d MMM yyyy HH:mm:ss Z\"\n\n        XCTAssertEqual(Date(\"2020-11-09T17:15:00Z\" as RBBJSON), Date(timeIntervalSince1970: 1604942100))\n        XCTAssertEqual(Date(\"Mon, 9 Nov 2020 17:15:00 +0000\" as RBBJSON, stringDecodingStrategoy: .formatted(formatter)), Date(timeIntervalSince1970: 1604942100))\n    }\n}\n"
  },
  {
    "path": "Tests/RBBJSONTests/NumbersTests.swift",
    "content": "import XCTest\n\nimport RBBJSON\n\n@available(iOS 10.0, *)\nfinal class NumbersTests: XCTestCase {\n    func testNumberConversion() {\n        do {\n            XCTAssertEqual(Int(\"foo\" as RBBJSON), nil)\n            XCTAssertEqual(Int(\"\"    as RBBJSON), nil)\n            XCTAssertEqual(Int(\"123.4\" as RBBJSON), nil)\n            XCTAssertEqual(Int(123.4 as RBBJSON), 123)\n            XCTAssertEqual(Int(0     as RBBJSON), 0)\n\n            XCTAssertEqual(Int(\"foo\" as RBBJSON, lenient: true), nil)\n            XCTAssertEqual(Int(\"\"    as RBBJSON, lenient: true), nil)\n            XCTAssertEqual(Int(\"123\" as RBBJSON, lenient: true), 123)\n            XCTAssertEqual(Int(\"123.4\" as RBBJSON, lenient: true), 123)\n            XCTAssertEqual(Int(123.4 as RBBJSON, lenient: true), 123)\n            XCTAssertEqual(Int(0     as RBBJSON, lenient: true), 0)\n        }\n\n        do {\n            XCTAssertEqual(UInt32(\"foo\" as RBBJSON), nil)\n            XCTAssertEqual(UInt32(\"\"    as RBBJSON), nil)\n            XCTAssertEqual(UInt32(\"123.4\" as RBBJSON), nil)\n            XCTAssertEqual(UInt32(123.4 as RBBJSON), 123)\n            XCTAssertEqual(UInt32(0     as RBBJSON), 0)\n\n            XCTAssertEqual(UInt32(\"foo\" as RBBJSON, lenient: true), nil)\n            XCTAssertEqual(UInt32(\"\"    as RBBJSON, lenient: true), nil)\n            XCTAssertEqual(UInt32(\"123\" as RBBJSON, lenient: true), 123)\n            XCTAssertEqual(UInt32(\"123.4\" as RBBJSON, lenient: true), 123)\n            XCTAssertEqual(UInt32(123.4 as RBBJSON, lenient: true), 123)\n            XCTAssertEqual(UInt32(0     as RBBJSON, lenient: true), 0)\n        }\n\n        #if canImport(CoreGraphics)\n        do {\n            XCTAssertEqual(CGFloat(\"foo\" as RBBJSON), nil)\n            XCTAssertEqual(CGFloat(\"\"    as RBBJSON), nil)\n            XCTAssertEqual(CGFloat(\"123.4\" as RBBJSON), nil)\n            XCTAssertEqual(CGFloat(123.4 as RBBJSON), 123.4)\n            XCTAssertEqual(CGFloat(0     as RBBJSON), 0)\n\n            XCTAssertEqual(CGFloat(\"foo\" as RBBJSON, lenient: true), nil)\n            XCTAssertEqual(CGFloat(\"\"    as RBBJSON, lenient: true), nil)\n            XCTAssertEqual(CGFloat(\"123.4\" as RBBJSON, lenient: true), 123.4)\n            XCTAssertEqual(CGFloat(123.4 as RBBJSON, lenient: true), 123.4)\n            XCTAssertEqual(CGFloat(0     as RBBJSON, lenient: true), 0)\n        }\n        #endif\n\n        do {\n            XCTAssertEqual(Double(\"foo\" as RBBJSON), nil)\n            XCTAssertEqual(Double(\"\"    as RBBJSON), nil)\n            XCTAssertEqual(Double(\"123.4\" as RBBJSON), nil)\n            XCTAssertEqual(Double(123.4 as RBBJSON), 123.4)\n            XCTAssertEqual(Double(0     as RBBJSON), 0)\n\n            XCTAssertEqual(Double(\"foo\" as RBBJSON, lenient: true), nil)\n            XCTAssertEqual(Double(\"\"    as RBBJSON, lenient: true), nil)\n            XCTAssertEqual(Double(\"123.4\" as RBBJSON, lenient: true), 123.4)\n            XCTAssertEqual(Double(123.4 as RBBJSON, lenient: true), 123.4)\n            XCTAssertEqual(Double(0     as RBBJSON, lenient: true), 0)\n        }\n\n        do {\n            XCTAssertEqual(Float(\"foo\" as RBBJSON), nil)\n            XCTAssertEqual(Float(\"\"    as RBBJSON), nil)\n            XCTAssertEqual(Float(\"123.4\" as RBBJSON), nil)\n            XCTAssertEqual(Float(123.4 as RBBJSON), 123.4)\n            XCTAssertEqual(Float(0     as RBBJSON), 0)\n\n            XCTAssertEqual(Float(\"foo\" as RBBJSON, lenient: true), nil)\n            XCTAssertEqual(Float(\"\"    as RBBJSON, lenient: true), nil)\n            XCTAssertEqual(Float(\"123.4\" as RBBJSON, lenient: true), 123.4)\n            XCTAssertEqual(Float(123.4 as RBBJSON, lenient: true), 123.4)\n            XCTAssertEqual(Float(0     as RBBJSON, lenient: true), 0)\n        }\n    }\n}\n"
  },
  {
    "path": "Tests/RBBJSONTests/QueryTests.swift",
    "content": "import XCTest\n\nimport RBBJSON\n\nprivate let json = [\n    \"store\": [\n        \"book\": [\n            [\n                \"category\": \"reference\",\n                \"author\": \"Nigel Rees\",\n                \"title\": \"Sayings of the Century\",\n                \"price\": 8.95\n            ],\n            [\n                \"category\": \"fiction\",\n                \"author\": \"Evelyn Waugh\",\n                \"title\": \"Sword of Honour\",\n                \"price\": 12.99\n            ],\n            [\n                \"category\": \"fiction\",\n                \"author\": \"Herman Melville\",\n                \"title\": \"Moby Dick\",\n                \"isbn\": \"0-553-21311-3\",\n                \"price\": 8.99\n            ],\n            [\n                \"category\": \"fiction\",\n                \"author\": \"J. R. R. Tolkien\",\n                \"title\": \"The Lord of the Rings\",\n                \"isbn\": \"0-395-19395-8\",\n                \"price\": 22.99\n            ]\n        ],\n        \"bicycle\": [\n            \"color\": \"red\",\n            \"price\": 19.95\n        ]\n    ],\n    \"expensive\": 10\n] as RBBJSON\n\nfinal class QueryTests: XCTestCase {\n    func testQueriesMultipleIndices() {\n        // JSONPath: $..book[0,1].price\n        RBBAssertEqual(json[any: .descendantOrSelf].book[0, 1].price, [\n            8.95,\n            12.99\n        ])\n    }\n\n    func testQueriesMultipleNegativeIndices() {\n        // JSONPath: $..book[-4,-3].price\n        RBBAssertEqual(json[any: .descendantOrSelf].book[-4, -3].price, [\n            8.95,\n            12.99\n        ])\n    }\n\n    func testRange() {\n        // JSONPath: $..book[1:2]\n        RBBAssertEqual(json[any: .descendantOrSelf].book[1..<2], [\n            [\n                \"category\": \"fiction\",\n                \"author\": \"Evelyn Waugh\",\n                \"title\": \"Sword of Honour\",\n                \"price\": 12.99\n            ]\n        ])\n    }\n\n    func testPredicateOnObject() {\n        // JSONPath: $.store.bicycle[?(@.price < 20)]\n        RBBAssertEqual(json.store.bicycle[matches: { $0.price <= 20 }], [\n            [\n                \"color\": \"red\",\n                \"price\": 19.95\n            ]\n        ])\n\n        // JSONPath: $.store.bicycle[?(@.price <= 20)].color\n        RBBAssertEqual(json.store.bicycle[matches: { $0.price <= 20 }].color, [\n            \"red\"\n        ])\n\n        // JSONPath: $.store[*][?(@.price <= 20)].color\n        //\n        // NOTE: This query doesn't seem to work in Gatling but does in Jayway.\n        RBBAssertEqual(json.store[any: .child][matches: { $0.price <= 20 }].color, [\n            \"red\"\n        ])\n    }\n\n    func testTrailingAnyOnArray() {\n        // JSONPath: $.store.books[*]\n        RBBAssertEqual(json.store.book[any: .child], [\n            [\n                \"category\": \"reference\",\n                \"author\": \"Nigel Rees\",\n                \"title\": \"Sayings of the Century\",\n                \"price\": 8.95\n            ],\n            [\n                \"category\": \"fiction\",\n                \"author\": \"Evelyn Waugh\",\n                \"title\": \"Sword of Honour\",\n                \"price\": 12.99\n            ],\n            [\n                \"category\": \"fiction\",\n                \"author\": \"Herman Melville\",\n                \"title\": \"Moby Dick\",\n                \"isbn\": \"0-553-21311-3\",\n                \"price\": 8.99\n            ],\n            [\n                \"category\": \"fiction\",\n                \"author\": \"J. R. R. Tolkien\",\n                \"title\": \"The Lord of the Rings\",\n                \"isbn\": \"0-395-19395-8\",\n                \"price\": 22.99\n            ]\n        ])\n    }\n\n    func testLaziness() {\n        var counter = 0;\n\n        let json = [\n            1, \"b\", \"c\", 4\n        ] as RBBJSON\n\n        XCTAssertEqual(counter, 0)\n\n        let query = json[matches: { _ in\n            counter += 1;\n\n            return true == true\n        }]\n\n        var results = query.lazy.map { $0 }.makeIterator()\n\n        XCTAssertEqual(counter, 0)\n\n        XCTAssertEqual(results.next(), 1)\n        XCTAssertEqual(counter, 1)\n\n        XCTAssertEqual(results.next(), \"b\")\n        XCTAssertEqual(counter, 2)\n\n        XCTAssertEqual(results.next(), \"c\")\n        XCTAssertEqual(counter, 3)\n    }\n\n    func testEagerness() {\n        var counter = 0;\n\n        let json = [\n            1, \"b\", \"c\", 4\n        ] as RBBJSON\n\n        XCTAssertEqual(counter, 0)\n\n        let query = json[matches: { _ in\n            counter += 1;\n\n            return true == true\n        }]\n\n        var results = query.map { $0 }.makeIterator()\n\n        XCTAssertEqual(counter, 4)\n\n        XCTAssertEqual(results.next(), 1)\n        XCTAssertEqual(counter, 4)\n\n        XCTAssertEqual(results.next(), \"b\")\n        XCTAssertEqual(counter, 4)\n\n        XCTAssertEqual(results.next(), \"c\")\n        XCTAssertEqual(counter, 4)\n    }\n\n    func testOrder() {\n        let json = [\n            \"numbers\": [\n                [1],\n                [2],\n                [3],\n                [4],\n            ]\n        ] as RBBJSON\n\n        RBBAssertEqual(json[any: .child][any: .child][any: .child], [1, 2, 3, 4])\n        RBBAssertEqual(json[any: .child][any: .child][0], [1, 2, 3, 4])\n        RBBAssertEqual(json[any: .child][0, 1, 2, 3][0], [1, 2, 3, 4])\n        RBBAssertEqual(json[any: .child][0..<4][0], [1, 2, 3, 4])\n        RBBAssertEqual(json[any: .child][0...3][0], [1, 2, 3, 4])\n        RBBAssertEqual(json.numbers[any: .child][0], [1, 2, 3, 4])\n        RBBAssertEqual(json.numbers[matches: { $0[0] >= 0 }][any: .child], [1, 2, 3, 4])\n    }\n\n    func testEmptyLeaves() {\n        let json = [\n            [\n                [:],\n                [\"empty\": [:]],\n                [\"also_empty\": []],\n                []\n            ],\n            []\n        ] as RBBJSON\n\n        let result = Array(json[any: .child][any: .child][any: .child][any: .child])\n\n        XCTAssert(result.isEmpty)\n    }\n\n    func testUnsupported() {\n        do {\n            let result = Array(json.store.bicycle[1, 2, 3])\n\n            XCTAssert(result.isEmpty)\n        }\n\n        do {\n            let result = Array(json.store.bicycle[1..<3])\n\n            XCTAssert(result.isEmpty)\n        }\n\n        do {\n            let result = Array(json.store.books[\"a\"])\n\n            XCTAssert(result.isEmpty)\n        }\n    }\n\n    func testFilters() throws {\n        let json = [\n            [\n                \"name\": \"a\",\n                \"flag\": nil\n            ],\n            [\n                \"name\": \"b\",\n                \"flag\": 5\n            ],\n            [\n                \"name\": \"c\",\n                \"flag\": 10\n            ]\n        ] as RBBJSON\n\n        RBBAssertEqual(json[has: \\.name].name, [\"a\", \"b\", \"c\"])\n        RBBAssertEqual(json[has: \\.flag].name, [\"b\", \"c\"])\n        RBBAssertEqual(json[has: \\.flag][matches: { $0.flag >= 7 }].name, [\n            \"c\"\n        ])\n    }\n}\n\nfunc RBBAssertEqual<S, T>(_ lhs: S, _ result: T, _ message: @autoclosure () -> String = \"\", file: StaticString = #filePath, line: UInt = #line) where S: Sequence, T: Sequence, T.Element == S.Element, S.Element: Equatable {\n    XCTAssertEqual(Array(lhs), Array(result), message(), file: file, line: line)\n}\n"
  },
  {
    "path": "Tests/RBBJSONTests/RBBJSON+Literals.swift",
    "content": "import RBBJSON\n\nextension RBBJSON: ExpressibleByNilLiteral {\n    public init(nilLiteral: ()) {\n        self = .null\n    }\n}\n\nextension RBBJSON: ExpressibleByBooleanLiteral {\n    public init(booleanLiteral value: BooleanLiteralType) {\n        self = .bool(value)\n    }\n}\n\nextension RBBJSON: ExpressibleByFloatLiteral {\n    public init(floatLiteral value: Double) {\n        self = .number(value)\n    }\n}\n\nextension RBBJSON: ExpressibleByStringLiteral {\n    public init(stringLiteral value: String) {\n        self = .string(value)\n    }\n}\n\nextension RBBJSON: ExpressibleByArrayLiteral {\n    public init(arrayLiteral elements: RBBJSON...) {\n        self = .array(elements)\n    }\n}\n\nextension RBBJSON: ExpressibleByIntegerLiteral {\n    public init(integerLiteral value: Int) {\n        self = .number(Double(value))\n    }\n}\n\nextension RBBJSON: ExpressibleByDictionaryLiteral {\n    public init(dictionaryLiteral elements: (String, RBBJSON)...) {\n        self = .object(Dictionary(elements) { a, _ in a })\n    }\n}\n"
  },
  {
    "path": "Tests/RBBJSONTests/RBBJSONTests.swift",
    "content": "import XCTest\n\nimport RBBJSON\n\nfinal class RBBJSONTests: XCTestCase {\n    func testJSONDecoding() throws {\n        let jsonString = \"\"\"\n        {\n            \"results\": [\n                {\n                    \"number\": -123.45,\n                    \"boolean\": false,\n                    \"string\": \"Hello World\",\n                },\n                {},\n                null\n            ]\n        }\n        \"\"\"\n\n        let json = try JSONDecoder().decode(RBBJSON.self, from: jsonString.data(using: .utf8)!)\n\n        XCTAssertEqual(json, [\n            \"results\": [\n                [\n                    \"number\": -123.45,\n                    \"boolean\": false,\n                    \"string\": \"Hello World\"\n                ],\n                [:],\n                nil\n            ]\n        ])\n    }\n\n    func testJSONRoundTripping() throws {\n        let json = [\n            \"results\": [\n                [\n                    \"number\": -123.45,\n                    \"boolean\": false,\n                    \"string\": \"Hello World\"\n                ]\n            ]\n        ] as RBBJSON\n\n        let jsonData = try JSONEncoder().encode(json)\n\n        XCTAssertEqual(json, try JSONDecoder().decode(RBBJSON.self, from: jsonData))\n    }\n\n    func testDebugDescription() {\n        let json = [\n            \"results\": [\n                [\n                    \"number\": -123.45,\n                    \"boolean\": false,\n                    \"string\": \"Hello World\"\n                ]\n            ]\n        ] as RBBJSON\n\n\n        XCTAssert(json.debugDescription.contains(\"Hello World\"))\n    }\n\n    func testDynamicKeypath() {\n        let json = [\n            \"results\": [\n                [\n                    \"number\": -123.45,\n                    \"boolean\": false,\n                    \"string\": \"Hello World\"\n                ]\n            ]\n        ] as RBBJSON\n\n        XCTAssertEqual(json.results[0].number, -123.45)\n        XCTAssertEqual(json.results[0].boolean, false)\n        XCTAssertEqual(json.results[0].string, \"Hello World\")\n    }\n\n    func testKeys() {\n        XCTAssertEqual(RBBJSON.keys(\"a\"), [])\n        XCTAssertEqual(RBBJSON.keys(1), [])\n        XCTAssertEqual(RBBJSON.keys(false), [])\n        XCTAssertEqual(RBBJSON.keys(nil), [])\n        XCTAssertEqual(RBBJSON.keys([1, 2, 3]), [])\n        XCTAssertEqual(RBBJSON.keys([\"a\": 1, \"b\": 2]), [\"a\", \"b\"])\n    }\n\n    func testValues() {\n        XCTAssertEqual(RBBJSON.values(\"a\"), [])\n        XCTAssertEqual(RBBJSON.values(1), [])\n        XCTAssertEqual(RBBJSON.values(false), [])\n        XCTAssertEqual(RBBJSON.values(nil), [])\n        XCTAssertEqual(RBBJSON.values([1, 2, 3]), [1, 2, 3])\n        XCTAssertEqual(RBBJSON.values([\"a\": 1, \"b\": 2]), [1, 2])\n    }\n}\n"
  },
  {
    "path": "Tests/RBBJSONTests/READMETests.swift",
    "content": "import XCTest\n\nimport RBBJSON\n\nprivate let json = [\n    \"store\": [\n        \"book\": [\n            [\n                \"category\": \"reference\",\n                \"author\": \"Nigel Rees\",\n                \"title\": \"Sayings of the Century\",\n                \"price\": 8.95\n            ],\n            [\n                \"category\": \"fiction\",\n                \"author\": \"Evelyn Waugh\",\n                \"title\": \"Sword of Honour\",\n                \"price\": 12.99\n            ],\n            [\n                \"category\": \"fiction\",\n                \"author\": \"Herman Melville\",\n                \"title\": \"Moby Dick\",\n                \"isbn\": \"0-553-21311-3\",\n                \"price\": 8.99\n            ],\n            [\n                \"category\": \"fiction\",\n                \"author\": \"J. R. R. Tolkien\",\n                \"title\": \"The Lord of the Rings\",\n                \"isbn\": \"0-395-19395-8\",\n                \"price\": 22.99\n            ]\n        ],\n        \"bicycle\": [\n            \"color\": \"red\",\n            \"price\": 19.95\n        ]\n    ],\n    \"expensive\": 10\n] as RBBJSON\n\nfinal class READMETests: XCTestCase {\n    func testQueriesAny() {\n        // JSONPath: $.store.book[*].author\n        RBBAssertEqual(json.store.book[any: .child].author, [\n            \"Nigel Rees\",\n            \"Evelyn Waugh\",\n            \"Herman Melville\",\n            \"J. R. R. Tolkien\"\n        ])\n    }\n\n    func testQueriesDescend() {\n        // JSONPath: $..author\n        RBBAssertEqual(json[any: .descendantOrSelf].author, [\n            \"Nigel Rees\",\n            \"Evelyn Waugh\",\n            \"Herman Melville\",\n            \"J. R. R. Tolkien\"\n        ])\n    }\n\n    func testQueriesAnyAtEnd() {\n        // JSONPath: $.store.*\n        RBBAssertEqual(json.store[any: .child], [\n            [\n                \"color\": \"red\",\n                \"price\": 19.95\n            ],\n            [\n                [\n                    \"category\": \"reference\",\n                    \"author\": \"Nigel Rees\",\n                    \"title\": \"Sayings of the Century\",\n                    \"price\": 8.95\n                ],\n                [\n                    \"category\": \"fiction\",\n                    \"author\": \"Evelyn Waugh\",\n                    \"title\": \"Sword of Honour\",\n                    \"price\": 12.99\n                ],\n                [\n                    \"category\": \"fiction\",\n                    \"author\": \"Herman Melville\",\n                    \"title\": \"Moby Dick\",\n                    \"isbn\": \"0-553-21311-3\",\n                    \"price\": 8.99\n                ],\n                [\n                    \"category\": \"fiction\",\n                    \"author\": \"J. R. R. Tolkien\",\n                    \"title\": \"The Lord of the Rings\",\n                    \"isbn\": \"0-395-19395-8\",\n                    \"price\": 22.99\n                ]\n            ]\n        ])\n    }\n\n    func testQueriesDescend2() {\n        // JSONPath: $.store..price\n        RBBAssertEqual(json.store[any: .descendantOrSelf].price, [\n            19.95,\n            8.95,\n            12.99,\n            8.99,\n            22.99\n        ])\n    }\n\n    func testQueriesSingleIndex() {\n        // JSONPath: $..book[2]\n        RBBAssertEqual(json[any: .descendantOrSelf].book[2], [\n            [\n                \"category\": \"fiction\",\n                \"author\": \"Herman Melville\",\n                \"title\": \"Moby Dick\",\n                \"isbn\": \"0-553-21311-3\",\n                \"price\": 8.99\n            ]\n        ])\n    }\n\n    func testQueriesNegativeIndex() {\n        // JSONPath: $..book[-2]\n        RBBAssertEqual(json[any: .descendantOrSelf].book[-2], [\n            [\n                \"category\": \"fiction\",\n                \"author\": \"Herman Melville\",\n                \"title\": \"Moby Dick\",\n                \"isbn\": \"0-553-21311-3\",\n                \"price\": 8.99\n            ]\n        ])\n    }\n\n    func testQueriesMultipleIndicesAtEnd() {\n        // JSONPath: $..book[0,1]\n        RBBAssertEqual(json[any: .descendantOrSelf].book[0, 1], [\n            [\n                \"category\": \"reference\",\n                \"author\": \"Nigel Rees\",\n                \"title\": \"Sayings of the Century\",\n                \"price\": 8.95\n            ],\n            [\n                \"category\": \"fiction\",\n                \"author\": \"Evelyn Waugh\",\n                \"title\": \"Sword of Honour\",\n                \"price\": 12.99\n            ]\n        ])\n    }\n\n    func testFilter() {\n        // JSONPath: $..book[?(@.isbn)]\n        RBBAssertEqual(json[any: .descendantOrSelf].book[has: \\.isbn], [\n            [\n                \"category\": \"fiction\",\n                \"author\": \"Herman Melville\",\n                \"title\": \"Moby Dick\",\n                \"isbn\": \"0-553-21311-3\",\n                \"price\": 8.99\n            ],\n            [\n                \"category\": \"fiction\",\n                \"author\": \"J. R. R. Tolkien\",\n                \"title\": \"The Lord of the Rings\",\n                \"isbn\": \"0-395-19395-8\",\n                \"price\": 22.99\n            ]\n        ])\n    }\n\n    func testBooleanPredicate() {\n        // JSONPath: $.store.book[?(@.price < 10)]\n        RBBAssertEqual(json.store.book[matches: { $0.price <= 10 }], [\n            [\n                \"category\": \"reference\",\n                \"author\": \"Nigel Rees\",\n                \"title\": \"Sayings of the Century\",\n                \"price\": 8.95\n            ],\n            [\n                \"category\": \"fiction\",\n                \"author\": \"Herman Melville\",\n                \"title\": \"Moby Dick\",\n                \"isbn\": \"0-553-21311-3\",\n                \"price\": 8.99\n            ]\n        ])\n    }\n\n    func testMultipleKeys() {\n        // JSONPath: $.store[\"book\", \"bicycle\"]..[\"price\", \"author\"]\n        //\n        // NOTE: This query doesn't seem to work in Gatling but does in Jayway\n        //       with slightly different semantics: Turning on _Return null for\n        //       missing leaf_ will produce the expected result although with a\n        //       `null` value for the bicycle's author that we're omitting here.\n        RBBAssertEqual(json.store[\"book\", \"bicycle\"][any: .descendantOrSelf][\"price\", \"author\"], [\n            [\n                \"price\": 19.95,\n            ],\n            [\n                \"price\": 8.95,\n                \"author\": \"Nigel Rees\"\n            ],\n            [\n                \"price\": 12.99,\n                \"author\": \"Evelyn Waugh\"\n            ],\n            [\n                \"price\": 8.99,\n                \"author\": \"Herman Melville\"\n            ],\n            [\n                \"price\": 22.99,\n                \"author\": \"J. R. R. Tolkien\"\n            ],\n        ])\n    }\n\n    func testExample() {\n        RBBAssertEqual(json.store.book[0].title.compactMap(String.init),    [\n            \"Sayings of the Century\"\n        ])\n        RBBAssertEqual(json.store.book[0, 1].title.compactMap(String.init), [\n            \"Sayings of the Century\",\n            \"Sword of Honour\"\n        ])\n\n        RBBAssertEqual(json.store.book[0][\"invalid Property\"].compactMap(String.init),    [])\n        RBBAssertEqual(json.store.book[0, 1][\"invalid Property\"].compactMap(String.init), [])\n\n    }\n}\n"
  },
  {
    "path": "Tests/RBBJSONTests/SequenceTests.swift",
    "content": "import XCTest\n\nimport RBBJSON\n\nfinal class SequenceTests: XCTestCase {\n    func testEnumeration() {\n        let json = [\n            \"results\": [\n                [\n                    \"number\": -123.45,\n                    \"boolean\": false,\n                    \"string\": \"Hello World\"\n                ]\n            ]\n        ] as RBBJSON\n\n        for results in RBBJSON.values(json) {\n            for result in RBBJSON.values(results) {\n                XCTAssertEqual(result.number, -123.45)\n                XCTAssertEqual(result.boolean, false)\n                XCTAssertEqual(result.string, \"Hello World\")\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Tests/RBBJSONTests/StringTests.swift",
    "content": "import XCTest\n\nimport RBBJSON\n\n@available(iOS 10.0, *)\nfinal class StringTests: XCTestCase {\n    func testStringConversion() {\n        XCTAssertEqual(String(\"foo\" as RBBJSON), \"foo\")\n        XCTAssertEqual(String(\"\"    as RBBJSON), \"\")\n        XCTAssertEqual(String(123.4 as RBBJSON), nil)\n        XCTAssertEqual(String(0     as RBBJSON), nil)\n    }\n}\n"
  }
]