packages feed

aeson-jsonpath 0.3.0.1 → 0.3.0.2

raw patch · 34 files changed

+14866/−12788 lines, 34 filesdep ~aesondep ~basedep ~template-haskellPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: aeson, base, template-haskell

API changes (from Hackage documentation)

- Data.Aeson.JSONPath.Query: class Queryable a
- Data.Aeson.JSONPath.Query: instance Data.Aeson.JSONPath.Query.Queryable Data.Aeson.JSONPath.Query.Types.Query
- Data.Aeson.JSONPath.Query: instance Data.Aeson.JSONPath.Query.Queryable Data.Aeson.JSONPath.Query.Types.QuerySegment
- Data.Aeson.JSONPath.Query: instance Data.Aeson.JSONPath.Query.Queryable Data.Aeson.JSONPath.Query.Types.Segment
- Data.Aeson.JSONPath.Query: instance Data.Aeson.JSONPath.Query.Queryable Data.Aeson.JSONPath.Query.Types.Selector
- Data.Aeson.JSONPath.Query: query' :: Queryable a => a -> Value -> Value -> Vector Value
- Data.Aeson.JSONPath.Query: queryLocated' :: Queryable a => a -> Value -> Value -> String -> Vector (String, Value)
- Data.Aeson.JSONPath.Query.Types: ArraySlice :: (Maybe Int, Maybe Int, Int) -> Selector
- Data.Aeson.JSONPath.Query.Types: Bracketed :: [Selector] -> Segment
- Data.Aeson.JSONPath.Query.Types: Child :: SegmentType
- Data.Aeson.JSONPath.Query.Types: Comp :: Comparable -> ComparisonOp -> Comparable -> ComparisonExpr
- Data.Aeson.JSONPath.Query.Types: CompLitBool :: Bool -> Comparable
- Data.Aeson.JSONPath.Query.Types: CompLitNull :: Comparable
- Data.Aeson.JSONPath.Query.Types: CompLitNum :: Scientific -> Comparable
- Data.Aeson.JSONPath.Query.Types: CompLitString :: Text -> Comparable
- Data.Aeson.JSONPath.Query.Types: CompSQ :: SingularQuery -> Comparable
- Data.Aeson.JSONPath.Query.Types: Comparison :: ComparisonExpr -> BasicExpr
- Data.Aeson.JSONPath.Query.Types: Current :: QueryType
- Data.Aeson.JSONPath.Query.Types: CurrentSQ :: SingularQueryType
- Data.Aeson.JSONPath.Query.Types: Descendant :: SegmentType
- Data.Aeson.JSONPath.Query.Types: Dotted :: Text -> Segment
- Data.Aeson.JSONPath.Query.Types: Equal :: ComparisonOp
- Data.Aeson.JSONPath.Query.Types: Filter :: LogicalOrExpr -> Selector
- Data.Aeson.JSONPath.Query.Types: Greater :: ComparisonOp
- Data.Aeson.JSONPath.Query.Types: GreaterOrEqual :: ComparisonOp
- Data.Aeson.JSONPath.Query.Types: Index :: Int -> Selector
- Data.Aeson.JSONPath.Query.Types: IndexSQSeg :: Int -> SingularQuerySegment
- Data.Aeson.JSONPath.Query.Types: Less :: ComparisonOp
- Data.Aeson.JSONPath.Query.Types: LessOrEqual :: ComparisonOp
- Data.Aeson.JSONPath.Query.Types: LogicalAnd :: [BasicExpr] -> LogicalAndExpr
- Data.Aeson.JSONPath.Query.Types: LogicalOr :: [LogicalAndExpr] -> LogicalOrExpr
- Data.Aeson.JSONPath.Query.Types: Name :: Text -> Selector
- Data.Aeson.JSONPath.Query.Types: NameSQSeg :: Text -> SingularQuerySegment
- Data.Aeson.JSONPath.Query.Types: NotEqual :: ComparisonOp
- Data.Aeson.JSONPath.Query.Types: NotParen :: LogicalOrExpr -> BasicExpr
- Data.Aeson.JSONPath.Query.Types: NotTest :: TestExpr -> BasicExpr
- Data.Aeson.JSONPath.Query.Types: Paren :: LogicalOrExpr -> BasicExpr
- Data.Aeson.JSONPath.Query.Types: Query :: QueryType -> [QuerySegment] -> Query
- Data.Aeson.JSONPath.Query.Types: QuerySegment :: SegmentType -> Segment -> QuerySegment
- Data.Aeson.JSONPath.Query.Types: Root :: QueryType
- Data.Aeson.JSONPath.Query.Types: RootSQ :: SingularQueryType
- Data.Aeson.JSONPath.Query.Types: SingularQuery :: SingularQueryType -> [SingularQuerySegment] -> SingularQuery
- Data.Aeson.JSONPath.Query.Types: Test :: TestExpr -> BasicExpr
- Data.Aeson.JSONPath.Query.Types: WildcardSegment :: Segment
- Data.Aeson.JSONPath.Query.Types: WildcardSelector :: Selector
- Data.Aeson.JSONPath.Query.Types: [querySegments] :: Query -> [QuerySegment]
- Data.Aeson.JSONPath.Query.Types: [queryType] :: Query -> QueryType
- Data.Aeson.JSONPath.Query.Types: [segmentType] :: QuerySegment -> SegmentType
- Data.Aeson.JSONPath.Query.Types: [segment] :: QuerySegment -> Segment
- Data.Aeson.JSONPath.Query.Types: [singularQuerySegments] :: SingularQuery -> [SingularQuerySegment]
- Data.Aeson.JSONPath.Query.Types: [singularQueryType] :: SingularQuery -> SingularQueryType
- Data.Aeson.JSONPath.Query.Types: data BasicExpr
- Data.Aeson.JSONPath.Query.Types: data Comparable
- Data.Aeson.JSONPath.Query.Types: data ComparisonExpr
- Data.Aeson.JSONPath.Query.Types: data ComparisonOp
- Data.Aeson.JSONPath.Query.Types: data Query
- Data.Aeson.JSONPath.Query.Types: data QuerySegment
- Data.Aeson.JSONPath.Query.Types: data QueryType
- Data.Aeson.JSONPath.Query.Types: data Segment
- Data.Aeson.JSONPath.Query.Types: data SegmentType
- Data.Aeson.JSONPath.Query.Types: data Selector
- Data.Aeson.JSONPath.Query.Types: data SingularQuery
- Data.Aeson.JSONPath.Query.Types: data SingularQuerySegment
- Data.Aeson.JSONPath.Query.Types: data SingularQueryType
- Data.Aeson.JSONPath.Query.Types: instance GHC.Classes.Eq Data.Aeson.JSONPath.Query.Types.BasicExpr
- Data.Aeson.JSONPath.Query.Types: instance GHC.Classes.Eq Data.Aeson.JSONPath.Query.Types.Comparable
- Data.Aeson.JSONPath.Query.Types: instance GHC.Classes.Eq Data.Aeson.JSONPath.Query.Types.ComparisonExpr
- Data.Aeson.JSONPath.Query.Types: instance GHC.Classes.Eq Data.Aeson.JSONPath.Query.Types.ComparisonOp
- Data.Aeson.JSONPath.Query.Types: instance GHC.Classes.Eq Data.Aeson.JSONPath.Query.Types.LogicalAndExpr
- Data.Aeson.JSONPath.Query.Types: instance GHC.Classes.Eq Data.Aeson.JSONPath.Query.Types.LogicalOrExpr
- Data.Aeson.JSONPath.Query.Types: instance GHC.Classes.Eq Data.Aeson.JSONPath.Query.Types.Query
- Data.Aeson.JSONPath.Query.Types: instance GHC.Classes.Eq Data.Aeson.JSONPath.Query.Types.QuerySegment
- Data.Aeson.JSONPath.Query.Types: instance GHC.Classes.Eq Data.Aeson.JSONPath.Query.Types.QueryType
- Data.Aeson.JSONPath.Query.Types: instance GHC.Classes.Eq Data.Aeson.JSONPath.Query.Types.Segment
- Data.Aeson.JSONPath.Query.Types: instance GHC.Classes.Eq Data.Aeson.JSONPath.Query.Types.SegmentType
- Data.Aeson.JSONPath.Query.Types: instance GHC.Classes.Eq Data.Aeson.JSONPath.Query.Types.Selector
- Data.Aeson.JSONPath.Query.Types: instance GHC.Classes.Eq Data.Aeson.JSONPath.Query.Types.SingularQuery
- Data.Aeson.JSONPath.Query.Types: instance GHC.Classes.Eq Data.Aeson.JSONPath.Query.Types.SingularQuerySegment
- Data.Aeson.JSONPath.Query.Types: instance GHC.Classes.Eq Data.Aeson.JSONPath.Query.Types.SingularQueryType
- Data.Aeson.JSONPath.Query.Types: instance GHC.Show.Show Data.Aeson.JSONPath.Query.Types.BasicExpr
- Data.Aeson.JSONPath.Query.Types: instance GHC.Show.Show Data.Aeson.JSONPath.Query.Types.Comparable
- Data.Aeson.JSONPath.Query.Types: instance GHC.Show.Show Data.Aeson.JSONPath.Query.Types.ComparisonExpr
- Data.Aeson.JSONPath.Query.Types: instance GHC.Show.Show Data.Aeson.JSONPath.Query.Types.ComparisonOp
- Data.Aeson.JSONPath.Query.Types: instance GHC.Show.Show Data.Aeson.JSONPath.Query.Types.LogicalAndExpr
- Data.Aeson.JSONPath.Query.Types: instance GHC.Show.Show Data.Aeson.JSONPath.Query.Types.LogicalOrExpr
- Data.Aeson.JSONPath.Query.Types: instance GHC.Show.Show Data.Aeson.JSONPath.Query.Types.Query
- Data.Aeson.JSONPath.Query.Types: instance GHC.Show.Show Data.Aeson.JSONPath.Query.Types.QuerySegment
- Data.Aeson.JSONPath.Query.Types: instance GHC.Show.Show Data.Aeson.JSONPath.Query.Types.QueryType
- Data.Aeson.JSONPath.Query.Types: instance GHC.Show.Show Data.Aeson.JSONPath.Query.Types.Segment
- Data.Aeson.JSONPath.Query.Types: instance GHC.Show.Show Data.Aeson.JSONPath.Query.Types.SegmentType
- Data.Aeson.JSONPath.Query.Types: instance GHC.Show.Show Data.Aeson.JSONPath.Query.Types.Selector
- Data.Aeson.JSONPath.Query.Types: instance GHC.Show.Show Data.Aeson.JSONPath.Query.Types.SingularQuery
- Data.Aeson.JSONPath.Query.Types: instance GHC.Show.Show Data.Aeson.JSONPath.Query.Types.SingularQuerySegment
- Data.Aeson.JSONPath.Query.Types: instance GHC.Show.Show Data.Aeson.JSONPath.Query.Types.SingularQueryType
- Data.Aeson.JSONPath.Query.Types: instance Language.Haskell.TH.Syntax.Lift Data.Aeson.JSONPath.Query.Types.BasicExpr
- Data.Aeson.JSONPath.Query.Types: instance Language.Haskell.TH.Syntax.Lift Data.Aeson.JSONPath.Query.Types.Comparable
- Data.Aeson.JSONPath.Query.Types: instance Language.Haskell.TH.Syntax.Lift Data.Aeson.JSONPath.Query.Types.ComparisonExpr
- Data.Aeson.JSONPath.Query.Types: instance Language.Haskell.TH.Syntax.Lift Data.Aeson.JSONPath.Query.Types.ComparisonOp
- Data.Aeson.JSONPath.Query.Types: instance Language.Haskell.TH.Syntax.Lift Data.Aeson.JSONPath.Query.Types.LogicalAndExpr
- Data.Aeson.JSONPath.Query.Types: instance Language.Haskell.TH.Syntax.Lift Data.Aeson.JSONPath.Query.Types.LogicalOrExpr
- Data.Aeson.JSONPath.Query.Types: instance Language.Haskell.TH.Syntax.Lift Data.Aeson.JSONPath.Query.Types.Query
- Data.Aeson.JSONPath.Query.Types: instance Language.Haskell.TH.Syntax.Lift Data.Aeson.JSONPath.Query.Types.QuerySegment
- Data.Aeson.JSONPath.Query.Types: instance Language.Haskell.TH.Syntax.Lift Data.Aeson.JSONPath.Query.Types.QueryType
- Data.Aeson.JSONPath.Query.Types: instance Language.Haskell.TH.Syntax.Lift Data.Aeson.JSONPath.Query.Types.Segment
- Data.Aeson.JSONPath.Query.Types: instance Language.Haskell.TH.Syntax.Lift Data.Aeson.JSONPath.Query.Types.SegmentType
- Data.Aeson.JSONPath.Query.Types: instance Language.Haskell.TH.Syntax.Lift Data.Aeson.JSONPath.Query.Types.Selector
- Data.Aeson.JSONPath.Query.Types: instance Language.Haskell.TH.Syntax.Lift Data.Aeson.JSONPath.Query.Types.SingularQuery
- Data.Aeson.JSONPath.Query.Types: instance Language.Haskell.TH.Syntax.Lift Data.Aeson.JSONPath.Query.Types.SingularQuerySegment
- Data.Aeson.JSONPath.Query.Types: instance Language.Haskell.TH.Syntax.Lift Data.Aeson.JSONPath.Query.Types.SingularQueryType
- Data.Aeson.JSONPath.Query.Types: newtype LogicalAndExpr
- Data.Aeson.JSONPath.Query.Types: newtype LogicalOrExpr
- Data.Aeson.JSONPath.Query.Types: type TestExpr = Query
+ Data.Aeson.JSONPath.Query: qQuery :: Query -> QueryState -> Vector Value
+ Data.Aeson.JSONPath.Query: qQueryLocated :: Query -> QueryState -> String -> Vector (String, Value)
+ Data.Aeson.JSONPath.Types: ArraySlice :: (Maybe Int, Maybe Int, Int) -> Selector a
+ Data.Aeson.JSONPath.Types: Bracketed :: [Selector a] -> Segment a
+ Data.Aeson.JSONPath.Types: Child :: SegmentType
+ Data.Aeson.JSONPath.Types: Comp :: Comparable -> ComparisonOp -> Comparable -> ComparisonExpr
+ Data.Aeson.JSONPath.Types: CompLit :: Literal -> Comparable
+ Data.Aeson.JSONPath.Types: CompSQ :: SingularQuery -> Comparable
+ Data.Aeson.JSONPath.Types: Comparison :: ComparisonExpr -> BasicExpr a
+ Data.Aeson.JSONPath.Types: Current :: QueryType
+ Data.Aeson.JSONPath.Types: CurrentSQ :: SingularQueryType
+ Data.Aeson.JSONPath.Types: Descendant :: SegmentType
+ Data.Aeson.JSONPath.Types: Dotted :: Text -> Segment a
+ Data.Aeson.JSONPath.Types: Equal :: ComparisonOp
+ Data.Aeson.JSONPath.Types: Filter :: LogicalOrExpr a -> Selector a
+ Data.Aeson.JSONPath.Types: FilterQuery :: a -> TestExpr a
+ Data.Aeson.JSONPath.Types: Greater :: ComparisonOp
+ Data.Aeson.JSONPath.Types: GreaterOrEqual :: ComparisonOp
+ Data.Aeson.JSONPath.Types: Index :: Int -> Selector a
+ Data.Aeson.JSONPath.Types: IndexSQSeg :: Int -> SingularQuerySegment
+ Data.Aeson.JSONPath.Types: Less :: ComparisonOp
+ Data.Aeson.JSONPath.Types: LessOrEqual :: ComparisonOp
+ Data.Aeson.JSONPath.Types: LitBool :: Bool -> Literal
+ Data.Aeson.JSONPath.Types: LitNull :: Literal
+ Data.Aeson.JSONPath.Types: LitNum :: Scientific -> Literal
+ Data.Aeson.JSONPath.Types: LitString :: Text -> Literal
+ Data.Aeson.JSONPath.Types: LogicalAnd :: [BasicExpr a] -> LogicalAndExpr a
+ Data.Aeson.JSONPath.Types: LogicalOr :: [LogicalAndExpr a] -> LogicalOrExpr a
+ Data.Aeson.JSONPath.Types: Name :: Text -> Selector a
+ Data.Aeson.JSONPath.Types: NameSQSeg :: Text -> SingularQuerySegment
+ Data.Aeson.JSONPath.Types: NotEqual :: ComparisonOp
+ Data.Aeson.JSONPath.Types: NotParen :: LogicalOrExpr a -> BasicExpr a
+ Data.Aeson.JSONPath.Types: NotTest :: TestExpr a -> BasicExpr a
+ Data.Aeson.JSONPath.Types: Paren :: LogicalOrExpr a -> BasicExpr a
+ Data.Aeson.JSONPath.Types: Query :: QueryType -> [QuerySegment Query] -> Query
+ Data.Aeson.JSONPath.Types: QuerySegment :: SegmentType -> Segment a -> QuerySegment a
+ Data.Aeson.JSONPath.Types: QueryState :: Value -> Value -> (Query -> QueryState -> Vector Value) -> QueryState
+ Data.Aeson.JSONPath.Types: Root :: QueryType
+ Data.Aeson.JSONPath.Types: RootSQ :: SingularQueryType
+ Data.Aeson.JSONPath.Types: SingularQuery :: SingularQueryType -> [SingularQuerySegment] -> SingularQuery
+ Data.Aeson.JSONPath.Types: Test :: TestExpr a -> BasicExpr a
+ Data.Aeson.JSONPath.Types: WildcardSegment :: Segment a
+ Data.Aeson.JSONPath.Types: WildcardSelector :: Selector a
+ Data.Aeson.JSONPath.Types: [curVal] :: QueryState -> Value
+ Data.Aeson.JSONPath.Types: [executeQuery] :: QueryState -> Query -> QueryState -> Vector Value
+ Data.Aeson.JSONPath.Types: [querySegments] :: Query -> [QuerySegment Query]
+ Data.Aeson.JSONPath.Types: [queryType] :: Query -> QueryType
+ Data.Aeson.JSONPath.Types: [rootVal] :: QueryState -> Value
+ Data.Aeson.JSONPath.Types: [segmentType] :: QuerySegment a -> SegmentType
+ Data.Aeson.JSONPath.Types: [segment] :: QuerySegment a -> Segment a
+ Data.Aeson.JSONPath.Types: [singularQuerySegments] :: SingularQuery -> [SingularQuerySegment]
+ Data.Aeson.JSONPath.Types: [singularQueryType] :: SingularQuery -> SingularQueryType
+ Data.Aeson.JSONPath.Types: data BasicExpr a
+ Data.Aeson.JSONPath.Types: data Comparable
+ Data.Aeson.JSONPath.Types: data ComparisonExpr
+ Data.Aeson.JSONPath.Types: data ComparisonOp
+ Data.Aeson.JSONPath.Types: data Literal
+ Data.Aeson.JSONPath.Types: data Query
+ Data.Aeson.JSONPath.Types: data QuerySegment a
+ Data.Aeson.JSONPath.Types: data QueryState
+ Data.Aeson.JSONPath.Types: data QueryType
+ Data.Aeson.JSONPath.Types: data Segment a
+ Data.Aeson.JSONPath.Types: data SegmentType
+ Data.Aeson.JSONPath.Types: data Selector a
+ Data.Aeson.JSONPath.Types: data SingularQuery
+ Data.Aeson.JSONPath.Types: data SingularQuerySegment
+ Data.Aeson.JSONPath.Types: data SingularQueryType
+ Data.Aeson.JSONPath.Types: newtype LogicalAndExpr a
+ Data.Aeson.JSONPath.Types: newtype LogicalOrExpr a
+ Data.Aeson.JSONPath.Types: newtype TestExpr a

Files

CHANGELOG.md view
@@ -2,6 +2,12 @@  All notable changes to this package are documented in this file. This project adheres to [Haskell PVP](https://pvp.haskell.org/) versioning. +## 0.3.0.2++- #43, Fix spaces not allowed in relative query and singular query segments+- #50, Fix wrong normalized path with descendant segment+- #30, Fix escape characters not handled properly in normalized path+ ## 0.3.0.1  - #31, Fix `test/cts.json` not included in hackage bundle
README.md view
@@ -1,6 +1,6 @@ # aeson-jsonpath -![ci-badge](https://github.com/taimoorzaeem/aeson-jsonpath/actions/workflows/build.yml/badge.svg?event=push) [![hackage-docs](https://img.shields.io/badge/hackage-v0.3.0.1-blue)](https://hackage.haskell.org/package/aeson-jsonpath) [![Donate](https://img.shields.io/badge/Donate-Patreon-red)](https://www.patreon.com/taimoorzaeem) ![Compliance](https://img.shields.io/badge/Compliance-Passing-brightgreen)+[![Build](https://github.com/taimoorzaeem/aeson-jsonpath/actions/workflows/build.yml/badge.svg)](https://github.com/taimoorzaeem/aeson-jsonpath/actions/workflows/build.yml) [![hackage-docs](https://img.shields.io/badge/hackage-v0.3.0.1-blue)](https://hackage.haskell.org/package/aeson-jsonpath) [![Donate](https://img.shields.io/badge/Donate-Patreon-red)](https://www.patreon.com/taimoorzaeem) [![Compliance](https://github.com/taimoorzaeem/aeson-jsonpath/actions/workflows/compliance.yml/badge.svg)](https://github.com/taimoorzaeem/aeson-jsonpath/actions/workflows/compliance.yml)  Run [RFC 9535](https://www.rfc-editor.org/rfc/rfc9535) compliant JSONPath queries on [Data.Aeson](https://hackage.haskell.org/package/aeson). @@ -15,10 +15,11 @@ - [x] Segments   - [x] Child Segment   - [x] Descendant Segment-- [x] Node Locations (Normalized Path)+- [x] Normalized Paths - [ ] Function Extensions-- [ ] Setting Values (Non-RFC) +I have decided not to implement Function Extension yet. Please open an issue or discussion if you'd like to see them implemented.+ ## Quick Start  ```haskell@@ -56,7 +57,7 @@         "year": 2018       },       {-        "title": "Lawrence Anyways",+        "title": "Laurence Anyways",         "director": "Xavier Dolan",         "year": 2012       }@@ -111,7 +112,7 @@ Right [   Object (fromList [     ("director",String "Xavier Dolan"),-    ("title",String "Lawrence Anyways"),+    ("title",String "Laurence Anyways"),     ("year",Number 2012.0)   ]) ]
aeson-jsonpath.cabal view
@@ -1,5 +1,5 @@ name:               aeson-jsonpath-version:            0.3.0.1+version:            0.3.0.2 synopsis:           Parse and run JSONPath queries on Aeson documents description:        RFC 9535 compliant JSONPath parsing and querying                     package. JSONPath is similar to XPath for querying@@ -14,7 +14,7 @@ build-type:         Simple extra-source-files: CHANGELOG.md extra-doc-files:    README.md-data-files:         test/cts.json+data-files:         jsonpath-compliance-test-suite/cts.json cabal-version:      1.18  tested-with:@@ -36,7 +36,20 @@   exposed-modules:    Data.Aeson.JSONPath                       Data.Aeson.JSONPath.Parser                       Data.Aeson.JSONPath.Query-                      Data.Aeson.JSONPath.Query.Types+                      Data.Aeson.JSONPath.Types+  other-modules:      Data.Aeson.JSONPath.Parser.Query+                      Data.Aeson.JSONPath.Parser.Filter+                      Data.Aeson.JSONPath.Parser.Name+                      Data.Aeson.JSONPath.Parser.Number+                      Data.Aeson.JSONPath.Parser.Common+                      Data.Aeson.JSONPath.Query.Query+                      Data.Aeson.JSONPath.Query.Segment+                      Data.Aeson.JSONPath.Query.Selector+                      Data.Aeson.JSONPath.Query.Filter+                      Data.Aeson.JSONPath.Types.Query+                      Data.Aeson.JSONPath.Types.Segment+                      Data.Aeson.JSONPath.Types.Selector+                      Data.Aeson.JSONPath.Types.Filter   build-depends:      aeson                     >= 2.0.3 && < 2.3                     , base                      >= 4.9 && < 4.22                     , parsec                    >= 3.1.11 && < 3.2@@ -53,12 +66,29 @@   default-extensions: OverloadedStrings                       NoImplicitPrelude                       QuasiQuotes-  hs-source-dirs:     test+  hs-source-dirs:     test/spec   main-is:            Main.hs   other-modules:      ParserSpec                       QuerySpec-                      ComplianceSpec                       LocatedSpec+  build-depends:      aeson                     >= 2.0.3 && < 2.3+                    , aeson-jsonpath+                    , base                      >= 4.9 && < 4.22+                    , hspec                     >= 2.3 && < 2.12+                    , parsec                    >= 3.1.11 && < 3.2+                    , vector                    >= 0.11 && < 0.14++  ghc-options:        -Wall -Wunused-packages++test-suite compliance+  type:               exitcode-stdio-1.0+  default-language:   Haskell2010+  default-extensions: OverloadedStrings+                      NoImplicitPrelude+                      QuasiQuotes+  hs-source-dirs:     test/compliance+  main-is:            Main.hs+  other-modules:      ComplianceSpec                       Paths_aeson_jsonpath   build-depends:      aeson                     >= 2.0.3 && < 2.3                     , aeson-jsonpath
+ jsonpath-compliance-test-suite/cts.json view
@@ -0,0 +1,12702 @@+{+  "description": "JSONPath Compliance Test Suite. This file is autogenerated, do not edit.",+  "tests": [+    {+      "name": "basic, root",+      "selector": "$",+      "document": [+        "first",+        "second"+      ],+      "result": [+        [+          "first",+          "second"+        ]+      ],+      "result_paths": [+        "$"+      ]+    },+    {+      "name": "basic, no leading whitespace",+      "selector": " $",+      "invalid_selector": true,+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "basic, no trailing whitespace",+      "selector": "$ ",+      "invalid_selector": true,+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "basic, name shorthand",+      "selector": "$.a",+      "document": {+        "a": "A",+        "b": "B"+      },+      "result": [+        "A"+      ],+      "result_paths": [+        "$['a']"+      ]+    },+    {+      "name": "basic, name shorthand, extended unicode ☺",+      "selector": "$.☺",+      "document": {+        "☺": "A",+        "b": "B"+      },+      "result": [+        "A"+      ],+      "result_paths": [+        "$['☺']"+      ]+    },+    {+      "name": "basic, name shorthand, underscore",+      "selector": "$._",+      "document": {+        "_": "A",+        "_foo": "B"+      },+      "result": [+        "A"+      ],+      "result_paths": [+        "$['_']"+      ]+    },+    {+      "name": "basic, name shorthand, symbol",+      "selector": "$.&",+      "invalid_selector": true+    },+    {+      "name": "basic, name shorthand, number",+      "selector": "$.1",+      "invalid_selector": true+    },+    {+      "name": "basic, name shorthand, absent data",+      "selector": "$.c",+      "document": {+        "a": "A",+        "b": "B"+      },+      "result": [],+      "result_paths": []+    },+    {+      "name": "basic, name shorthand, array data",+      "selector": "$.a",+      "document": [+        "first",+        "second"+      ],+      "result": [],+      "result_paths": []+    },+    {+      "name": "basic, name shorthand, object data, nested",+      "selector": "$.a.b.c",+      "document": {+        "a": {+          "b": {+            "c": "C"+          }+        }+      },+      "result": [+        "C"+      ],+      "result_paths": [+        "$['a']['b']['c']"+      ]+    },+    {+      "name": "basic, wildcard shorthand, object data",+      "selector": "$.*",+      "document": {+        "a": "A",+        "b": "B"+      },+      "results": [+        [+          "A",+          "B"+        ],+        [+          "B",+          "A"+        ]+      ],+      "results_paths": [+        [+          "$['a']",+          "$['b']"+        ],+        [+          "$['b']",+          "$['a']"+        ]+      ]+    },+    {+      "name": "basic, wildcard shorthand, array data",+      "selector": "$.*",+      "document": [+        "first",+        "second"+      ],+      "result": [+        "first",+        "second"+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ]+    },+    {+      "name": "basic, wildcard selector, array data",+      "selector": "$[*]",+      "document": [+        "first",+        "second"+      ],+      "result": [+        "first",+        "second"+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ]+    },+    {+      "name": "basic, wildcard shorthand, then name shorthand",+      "selector": "$.*.a",+      "document": {+        "x": {+          "a": "Ax",+          "b": "Bx"+        },+        "y": {+          "a": "Ay",+          "b": "By"+        }+      },+      "results": [+        [+          "Ax",+          "Ay"+        ],+        [+          "Ay",+          "Ax"+        ]+      ],+      "results_paths": [+        [+          "$['x']['a']",+          "$['y']['a']"+        ],+        [+          "$['y']['a']",+          "$['x']['a']"+        ]+      ]+    },+    {+      "name": "basic, multiple selectors",+      "selector": "$[0,2]",+      "document": [+        0,+        1,+        2,+        3,+        4,+        5,+        6,+        7,+        8,+        9+      ],+      "result": [+        0,+        2+      ],+      "result_paths": [+        "$[0]",+        "$[2]"+      ]+    },+    {+      "name": "basic, multiple selectors, space instead of comma",+      "selector": "$[0 2]",+      "invalid_selector": true,+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "basic, selector, leading comma",+      "selector": "$[,0]",+      "invalid_selector": true+    },+    {+      "name": "basic, selector, trailing comma",+      "selector": "$[0,]",+      "invalid_selector": true+    },+    {+      "name": "basic, multiple selectors, name and index, array data",+      "selector": "$['a',1]",+      "document": [+        0,+        1,+        2,+        3,+        4,+        5,+        6,+        7,+        8,+        9+      ],+      "result": [+        1+      ],+      "result_paths": [+        "$[1]"+      ]+    },+    {+      "name": "basic, multiple selectors, name and index, object data",+      "selector": "$['a',1]",+      "document": {+        "a": 1,+        "b": 2+      },+      "result": [+        1+      ],+      "result_paths": [+        "$['a']"+      ]+    },+    {+      "name": "basic, multiple selectors, index and slice",+      "selector": "$[1,5:7]",+      "document": [+        0,+        1,+        2,+        3,+        4,+        5,+        6,+        7,+        8,+        9+      ],+      "result": [+        1,+        5,+        6+      ],+      "result_paths": [+        "$[1]",+        "$[5]",+        "$[6]"+      ]+    },+    {+      "name": "basic, multiple selectors, index and slice, overlapping",+      "selector": "$[1,0:3]",+      "document": [+        0,+        1,+        2,+        3,+        4,+        5,+        6,+        7,+        8,+        9+      ],+      "result": [+        1,+        0,+        1,+        2+      ],+      "result_paths": [+        "$[1]",+        "$[0]",+        "$[1]",+        "$[2]"+      ]+    },+    {+      "name": "basic, multiple selectors, duplicate index",+      "selector": "$[1,1]",+      "document": [+        0,+        1,+        2,+        3,+        4,+        5,+        6,+        7,+        8,+        9+      ],+      "result": [+        1,+        1+      ],+      "result_paths": [+        "$[1]",+        "$[1]"+      ]+    },+    {+      "name": "basic, multiple selectors, wildcard and index",+      "selector": "$[*,1]",+      "document": [+        0,+        1,+        2,+        3,+        4,+        5,+        6,+        7,+        8,+        9+      ],+      "result": [+        0,+        1,+        2,+        3,+        4,+        5,+        6,+        7,+        8,+        9,+        1+      ],+      "result_paths": [+        "$[0]",+        "$[1]",+        "$[2]",+        "$[3]",+        "$[4]",+        "$[5]",+        "$[6]",+        "$[7]",+        "$[8]",+        "$[9]",+        "$[1]"+      ]+    },+    {+      "name": "basic, multiple selectors, wildcard and name",+      "selector": "$[*,'a']",+      "document": {+        "a": "A",+        "b": "B"+      },+      "results": [+        [+          "A",+          "B",+          "A"+        ],+        [+          "B",+          "A",+          "A"+        ]+      ],+      "results_paths": [+        [+          "$['a']",+          "$['b']",+          "$['a']"+        ],+        [+          "$['b']",+          "$['a']",+          "$['a']"+        ]+      ]+    },+    {+      "name": "basic, multiple selectors, wildcard and slice",+      "selector": "$[*,0:2]",+      "document": [+        0,+        1,+        2,+        3,+        4,+        5,+        6,+        7,+        8,+        9+      ],+      "result": [+        0,+        1,+        2,+        3,+        4,+        5,+        6,+        7,+        8,+        9,+        0,+        1+      ],+      "result_paths": [+        "$[0]",+        "$[1]",+        "$[2]",+        "$[3]",+        "$[4]",+        "$[5]",+        "$[6]",+        "$[7]",+        "$[8]",+        "$[9]",+        "$[0]",+        "$[1]"+      ]+    },+    {+      "name": "basic, multiple selectors, multiple wildcards",+      "selector": "$[*,*]",+      "document": [+        0,+        1,+        2+      ],+      "result": [+        0,+        1,+        2,+        0,+        1,+        2+      ],+      "result_paths": [+        "$[0]",+        "$[1]",+        "$[2]",+        "$[0]",+        "$[1]",+        "$[2]"+      ]+    },+    {+      "name": "basic, empty segment",+      "selector": "$[]",+      "invalid_selector": true+    },+    {+      "name": "basic, descendant segment, index",+      "selector": "$..[1]",+      "document": {+        "o": [+          0,+          1,+          [+            2,+            3+          ]+        ]+      },+      "result": [+        1,+        3+      ],+      "result_paths": [+        "$['o'][1]",+        "$['o'][2][1]"+      ]+    },+    {+      "name": "basic, descendant segment, name shorthand",+      "selector": "$..a",+      "document": {+        "o": [+          {+            "a": "b"+          },+          {+            "a": "c"+          }+        ]+      },+      "result": [+        "b",+        "c"+      ],+      "result_paths": [+        "$['o'][0]['a']",+        "$['o'][1]['a']"+      ]+    },+    {+      "name": "basic, descendant segment, wildcard shorthand, array data",+      "selector": "$..*",+      "document": [+        0,+        1+      ],+      "result": [+        0,+        1+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ]+    },+    {+      "name": "basic, descendant segment, wildcard selector, array data",+      "selector": "$..[*]",+      "document": [+        0,+        1+      ],+      "result": [+        0,+        1+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ]+    },+    {+      "name": "basic, descendant segment, wildcard selector, nested arrays",+      "selector": "$..[*]",+      "document": [+        [+          [+            1+          ]+        ],+        [+          2+        ]+      ],+      "results": [+        [+          [+            [+              1+            ]+          ],+          [+            2+          ],+          [+            1+          ],+          1,+          2+        ],+        [+          [+            [+              1+            ]+          ],+          [+            2+          ],+          [+            1+          ],+          2,+          1+        ]+      ],+      "results_paths": [+        [+          "$[0]",+          "$[1]",+          "$[0][0]",+          "$[0][0][0]",+          "$[1][0]"+        ],+        [+          "$[0]",+          "$[1]",+          "$[0][0]",+          "$[1][0]",+          "$[0][0][0]"+        ]+      ]+    },+    {+      "name": "basic, descendant segment, wildcard selector, nested objects",+      "selector": "$..[*]",+      "document": {+        "a": {+          "c": {+            "e": 1+          }+        },+        "b": {+          "d": 2+        }+      },+      "results": [+        [+          {+            "c": {+              "e": 1+            }+          },+          {+            "d": 2+          },+          {+            "e": 1+          },+          1,+          2+        ],+        [+          {+            "c": {+              "e": 1+            }+          },+          {+            "d": 2+          },+          {+            "e": 1+          },+          2,+          1+        ],+        [+          {+            "c": {+              "e": 1+            }+          },+          {+            "d": 2+          },+          2,+          {+            "e": 1+          },+          1+        ],+        [+          {+            "d": 2+          },+          {+            "c": {+              "e": 1+            }+          },+          {+            "e": 1+          },+          1,+          2+        ],+        [+          {+            "d": 2+          },+          {+            "c": {+              "e": 1+            }+          },+          {+            "e": 1+          },+          2,+          1+        ],+        [+          {+            "d": 2+          },+          {+            "c": {+              "e": 1+            }+          },+          2,+          {+            "e": 1+          },+          1+        ]+      ],+      "results_paths": [+        [+          "$['a']",+          "$['b']",+          "$['a']['c']",+          "$['a']['c']['e']",+          "$['b']['d']"+        ],+        [+          "$['a']",+          "$['b']",+          "$['a']['c']",+          "$['b']['d']",+          "$['a']['c']['e']"+        ],+        [+          "$['a']",+          "$['b']",+          "$['b']['d']",+          "$['a']['c']",+          "$['a']['c']['e']"+        ],+        [+          "$['b']",+          "$['a']",+          "$['a']['c']",+          "$['a']['c']['e']",+          "$['b']['d']"+        ],+        [+          "$['b']",+          "$['a']",+          "$['a']['c']",+          "$['b']['d']",+          "$['a']['c']['e']"+        ],+        [+          "$['b']",+          "$['a']",+          "$['b']['d']",+          "$['a']['c']",+          "$['a']['c']['e']"+        ]+      ]+    },+    {+      "name": "basic, descendant segment, wildcard shorthand, object data",+      "selector": "$..*",+      "document": {+        "a": "b"+      },+      "result": [+        "b"+      ],+      "result_paths": [+        "$['a']"+      ]+    },+    {+      "name": "basic, descendant segment, wildcard shorthand, nested data",+      "selector": "$..*",+      "document": {+        "o": [+          {+            "a": "b"+          }+        ]+      },+      "result": [+        [+          {+            "a": "b"+          }+        ],+        {+          "a": "b"+        },+        "b"+      ],+      "result_paths": [+        "$['o']",+        "$['o'][0]",+        "$['o'][0]['a']"+      ]+    },+    {+      "name": "basic, descendant segment, multiple selectors",+      "selector": "$..['a','d']",+      "document": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        }+      ],+      "result": [+        "b",+        "e",+        "c",+        "f"+      ],+      "result_paths": [+        "$[0]['a']",+        "$[0]['d']",+        "$[1]['a']",+        "$[1]['d']"+      ]+    },+    {+      "name": "basic, descendant segment, object traversal, multiple selectors",+      "selector": "$..['a','d']",+      "document": {+        "x": {+          "a": "b",+          "d": "e"+        },+        "y": {+          "a": "c",+          "d": "f"+        }+      },+      "results": [+        [+          "b",+          "e",+          "c",+          "f"+        ],+        [+          "c",+          "f",+          "b",+          "e"+        ]+      ],+      "results_paths": [+        [+          "$['x']['a']",+          "$['x']['d']",+          "$['y']['a']",+          "$['y']['d']"+        ],+        [+          "$['y']['a']",+          "$['y']['d']",+          "$['x']['a']",+          "$['x']['d']"+        ]+      ]+    },+    {+      "name": "basic, bald descendant segment",+      "selector": "$..",+      "invalid_selector": true+    },+    {+      "name": "basic, current node identifier without filter selector",+      "selector": "$[@.a]",+      "invalid_selector": true+    },+    {+      "name": "basic, root node identifier in brackets without filter selector",+      "selector": "$[$.a]",+      "invalid_selector": true+    },+    {+      "name": "filter, existence, without segments",+      "selector": "$[?@]",+      "document": {+        "a": 1,+        "b": null+      },+      "results": [+        [+          1,+          null+        ],+        [+          null,+          1+        ]+      ],+      "results_paths": [+        [+          "$['a']",+          "$['b']"+        ],+        [+          "$['b']",+          "$['a']"+        ]+      ]+    },+    {+      "name": "filter, existence",+      "selector": "$[?@.a]",+      "document": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "b": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "b",+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ]+    },+    {+      "name": "filter, existence, present with null",+      "selector": "$[?@.a]",+      "document": [+        {+          "a": null,+          "d": "e"+        },+        {+          "b": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": null,+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ]+    },+    {+      "name": "filter, absolute existence, without segments",+      "selector": "$[?$]",+      "document": {+        "a": 1,+        "b": null+      },+      "results": [+        [+          1,+          null+        ],+        [+          null,+          1+        ]+      ],+      "results_paths": [+        [+          "$['a']",+          "$['b']"+        ],+        [+          "$['b']",+          "$['a']"+        ]+      ]+    },+    {+      "name": "filter, absolute existence, with segments",+      "selector": "$[?$.*.a]",+      "document": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "b": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "b": "c",+          "d": "f"+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ]+    },+    {+      "name": "filter, equals string, single quotes",+      "selector": "$[?@.a=='b']",+      "document": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "b",+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ]+    },+    {+      "name": "filter, equals numeric string, single quotes",+      "selector": "$[?@.a=='1']",+      "document": [+        {+          "a": "1",+          "d": "e"+        },+        {+          "a": 1,+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "1",+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ]+    },+    {+      "name": "filter, equals string, double quotes",+      "selector": "$[?@.a==\"b\"]",+      "document": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "b",+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ]+    },+    {+      "name": "filter, equals numeric string, double quotes",+      "selector": "$[?@.a==\"1\"]",+      "document": [+        {+          "a": "1",+          "d": "e"+        },+        {+          "a": 1,+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "1",+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ]+    },+    {+      "name": "filter, equals number",+      "selector": "$[?@.a==1]",+      "document": [+        {+          "a": 1,+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        },+        {+          "a": 2,+          "d": "f"+        },+        {+          "a": "1",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": 1,+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ]+    },+    {+      "name": "filter, equals null",+      "selector": "$[?@.a==null]",+      "document": [+        {+          "a": null,+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": null,+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ]+    },+    {+      "name": "filter, equals null, absent from data",+      "selector": "$[?@.a==null]",+      "document": [+        {+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        }+      ],+      "result": [],+      "result_paths": []+    },+    {+      "name": "filter, equals true",+      "selector": "$[?@.a==true]",+      "document": [+        {+          "a": true,+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": true,+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ]+    },+    {+      "name": "filter, equals false",+      "selector": "$[?@.a==false]",+      "document": [+        {+          "a": false,+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": false,+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ]+    },+    {+      "name": "filter, equals self",+      "selector": "$[?@==@]",+      "document": [+        1,+        null,+        true,+        {+          "a": "b"+        },+        [+          false+        ]+      ],+      "result": [+        1,+        null,+        true,+        {+          "a": "b"+        },+        [+          false+        ]+      ],+      "result_paths": [+        "$[0]",+        "$[1]",+        "$[2]",+        "$[3]",+        "$[4]"+      ]+    },+    {+      "name": "filter, absolute, equals self",+      "selector": "$[?$==$]",+      "document": [+        1,+        null,+        true,+        {+          "a": "b"+        },+        [+          false+        ]+      ],+      "result": [+        1,+        null,+        true,+        {+          "a": "b"+        },+        [+          false+        ]+      ],+      "result_paths": [+        "$[0]",+        "$[1]",+        "$[2]",+        "$[3]",+        "$[4]"+      ]+    },+    {+      "name": "filter, equals, absent from index selector equals absent from name selector",+      "selector": "$[?@.absent==@.list[9]]",+      "document": [+        {+          "list": [+            1+          ]+        }+      ],+      "result": [+        {+          "list": [+            1+          ]+        }+      ],+      "result_paths": [+        "$[0]"+      ]+    },+    {+      "name": "filter, deep equality, arrays",+      "selector": "$[?@.a==@.b]",+      "document": [+        {+          "a": false,+          "b": [+            1,+            2+          ]+        },+        {+          "a": [+            [+              1,+              [+                2+              ]+            ]+          ],+          "b": [+            [+              1,+              [+                2+              ]+            ]+          ]+        },+        {+          "a": [+            [+              1,+              [+                2+              ]+            ]+          ],+          "b": [+            [+              [+                2+              ],+              1+            ]+          ]+        },+        {+          "a": [+            [+              1,+              [+                2+              ]+            ]+          ],+          "b": [+            [+              1,+              2+            ]+          ]+        }+      ],+      "result": [+        {+          "a": [+            [+              1,+              [+                2+              ]+            ]+          ],+          "b": [+            [+              1,+              [+                2+              ]+            ]+          ]+        }+      ],+      "result_paths": [+        "$[1]"+      ]+    },+    {+      "name": "filter, deep equality, objects",+      "selector": "$[?@.a==@.b]",+      "document": [+        {+          "a": false,+          "b": {+            "x": 1,+            "y": {+              "z": 1+            }+          }+        },+        {+          "a": {+            "x": 1,+            "y": {+              "z": 1+            }+          },+          "b": {+            "x": 1,+            "y": {+              "z": 1+            }+          }+        },+        {+          "a": {+            "x": 1,+            "y": {+              "z": 1+            }+          },+          "b": {+            "y": {+              "z": 1+            },+            "x": 1+          }+        },+        {+          "a": {+            "x": 1,+            "y": {+              "z": 1+            }+          },+          "b": {+            "x": 1+          }+        },+        {+          "a": {+            "x": 1,+            "y": {+              "z": 1+            }+          },+          "b": {+            "x": 1,+            "y": {+              "z": 2+            }+          }+        }+      ],+      "result": [+        {+          "a": {+            "x": 1,+            "y": {+              "z": 1+            }+          },+          "b": {+            "x": 1,+            "y": {+              "z": 1+            }+          }+        },+        {+          "a": {+            "x": 1,+            "y": {+              "z": 1+            }+          },+          "b": {+            "y": {+              "z": 1+            },+            "x": 1+          }+        }+      ],+      "result_paths": [+        "$[1]",+        "$[2]"+      ]+    },+    {+      "name": "filter, not-equals string, single quotes",+      "selector": "$[?@.a!='b']",+      "document": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "c",+          "d": "f"+        }+      ],+      "result_paths": [+        "$[1]"+      ]+    },+    {+      "name": "filter, not-equals numeric string, single quotes",+      "selector": "$[?@.a!='1']",+      "document": [+        {+          "a": "1",+          "d": "e"+        },+        {+          "a": 1,+          "d": "f"+        }+      ],+      "result": [+        {+          "a": 1,+          "d": "f"+        }+      ],+      "result_paths": [+        "$[1]"+      ]+    },+    {+      "name": "filter, not-equals string, single quotes, different type",+      "selector": "$[?@.a!='b']",+      "document": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "a": 1,+          "d": "f"+        }+      ],+      "result": [+        {+          "a": 1,+          "d": "f"+        }+      ],+      "result_paths": [+        "$[1]"+      ]+    },+    {+      "name": "filter, not-equals string, double quotes",+      "selector": "$[?@.a!=\"b\"]",+      "document": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "c",+          "d": "f"+        }+      ],+      "result_paths": [+        "$[1]"+      ]+    },+    {+      "name": "filter, not-equals numeric string, double quotes",+      "selector": "$[?@.a!=\"1\"]",+      "document": [+        {+          "a": "1",+          "d": "e"+        },+        {+          "a": 1,+          "d": "f"+        }+      ],+      "result": [+        {+          "a": 1,+          "d": "f"+        }+      ],+      "result_paths": [+        "$[1]"+      ]+    },+    {+      "name": "filter, not-equals string, double quotes, different types",+      "selector": "$[?@.a!=\"b\"]",+      "document": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "a": 1,+          "d": "f"+        }+      ],+      "result": [+        {+          "a": 1,+          "d": "f"+        }+      ],+      "result_paths": [+        "$[1]"+      ]+    },+    {+      "name": "filter, not-equals number",+      "selector": "$[?@.a!=1]",+      "document": [+        {+          "a": 1,+          "d": "e"+        },+        {+          "a": 2,+          "d": "f"+        },+        {+          "a": "1",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": 2,+          "d": "f"+        },+        {+          "a": "1",+          "d": "f"+        }+      ],+      "result_paths": [+        "$[1]",+        "$[2]"+      ]+    },+    {+      "name": "filter, not-equals number, different types",+      "selector": "$[?@.a!=1]",+      "document": [+        {+          "a": 1,+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "c",+          "d": "f"+        }+      ],+      "result_paths": [+        "$[1]"+      ]+    },+    {+      "name": "filter, not-equals null",+      "selector": "$[?@.a!=null]",+      "document": [+        {+          "a": null,+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "c",+          "d": "f"+        }+      ],+      "result_paths": [+        "$[1]"+      ]+    },+    {+      "name": "filter, not-equals null, absent from data",+      "selector": "$[?@.a!=null]",+      "document": [+        {+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ]+    },+    {+      "name": "filter, not-equals true",+      "selector": "$[?@.a!=true]",+      "document": [+        {+          "a": true,+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "c",+          "d": "f"+        }+      ],+      "result_paths": [+        "$[1]"+      ]+    },+    {+      "name": "filter, not-equals false",+      "selector": "$[?@.a!=false]",+      "document": [+        {+          "a": false,+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "c",+          "d": "f"+        }+      ],+      "result_paths": [+        "$[1]"+      ]+    },+    {+      "name": "filter, less than string, single quotes",+      "selector": "$[?@.a<'c']",+      "document": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "b",+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ]+    },+    {+      "name": "filter, less than string, double quotes",+      "selector": "$[?@.a<\"c\"]",+      "document": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "b",+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ]+    },+    {+      "name": "filter, less than number",+      "selector": "$[?@.a<10]",+      "document": [+        {+          "a": 1,+          "d": "e"+        },+        {+          "a": 10,+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        },+        {+          "a": 20,+          "d": "f"+        }+      ],+      "result": [+        {+          "a": 1,+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ]+    },+    {+      "name": "filter, less than null",+      "selector": "$[?@.a<null]",+      "document": [+        {+          "a": null,+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        }+      ],+      "result": [],+      "result_paths": []+    },+    {+      "name": "filter, less than true",+      "selector": "$[?@.a<true]",+      "document": [+        {+          "a": true,+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        }+      ],+      "result": [],+      "result_paths": []+    },+    {+      "name": "filter, less than false",+      "selector": "$[?@.a<false]",+      "document": [+        {+          "a": false,+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        }+      ],+      "result": [],+      "result_paths": []+    },+    {+      "name": "filter, less than or equal to string, single quotes",+      "selector": "$[?@.a<='c']",+      "document": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ]+    },+    {+      "name": "filter, less than or equal to string, double quotes",+      "selector": "$[?@.a<=\"c\"]",+      "document": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ]+    },+    {+      "name": "filter, less than or equal to number",+      "selector": "$[?@.a<=10]",+      "document": [+        {+          "a": 1,+          "d": "e"+        },+        {+          "a": 10,+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        },+        {+          "a": 20,+          "d": "f"+        }+      ],+      "result": [+        {+          "a": 1,+          "d": "e"+        },+        {+          "a": 10,+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ]+    },+    {+      "name": "filter, less than or equal to null",+      "selector": "$[?@.a<=null]",+      "document": [+        {+          "a": null,+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": null,+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ]+    },+    {+      "name": "filter, less than or equal to true",+      "selector": "$[?@.a<=true]",+      "document": [+        {+          "a": true,+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": true,+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ]+    },+    {+      "name": "filter, less than or equal to false",+      "selector": "$[?@.a<=false]",+      "document": [+        {+          "a": false,+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": false,+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ]+    },+    {+      "name": "filter, greater than string, single quotes",+      "selector": "$[?@.a>'c']",+      "document": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        },+        {+          "a": "d",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "d",+          "d": "f"+        }+      ],+      "result_paths": [+        "$[2]"+      ]+    },+    {+      "name": "filter, greater than string, double quotes",+      "selector": "$[?@.a>\"c\"]",+      "document": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        },+        {+          "a": "d",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "d",+          "d": "f"+        }+      ],+      "result_paths": [+        "$[2]"+      ]+    },+    {+      "name": "filter, greater than number",+      "selector": "$[?@.a>10]",+      "document": [+        {+          "a": 1,+          "d": "e"+        },+        {+          "a": 10,+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        },+        {+          "a": 20,+          "d": "f"+        }+      ],+      "result": [+        {+          "a": 20,+          "d": "f"+        }+      ],+      "result_paths": [+        "$[3]"+      ]+    },+    {+      "name": "filter, greater than null",+      "selector": "$[?@.a>null]",+      "document": [+        {+          "a": null,+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        }+      ],+      "result": [],+      "result_paths": []+    },+    {+      "name": "filter, greater than true",+      "selector": "$[?@.a>true]",+      "document": [+        {+          "a": true,+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        }+      ],+      "result": [],+      "result_paths": []+    },+    {+      "name": "filter, greater than false",+      "selector": "$[?@.a>false]",+      "document": [+        {+          "a": false,+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        }+      ],+      "result": [],+      "result_paths": []+    },+    {+      "name": "filter, greater than or equal to string, single quotes",+      "selector": "$[?@.a>='c']",+      "document": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        },+        {+          "a": "d",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "c",+          "d": "f"+        },+        {+          "a": "d",+          "d": "f"+        }+      ],+      "result_paths": [+        "$[1]",+        "$[2]"+      ]+    },+    {+      "name": "filter, greater than or equal to string, double quotes",+      "selector": "$[?@.a>=\"c\"]",+      "document": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        },+        {+          "a": "d",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "c",+          "d": "f"+        },+        {+          "a": "d",+          "d": "f"+        }+      ],+      "result_paths": [+        "$[1]",+        "$[2]"+      ]+    },+    {+      "name": "filter, greater than or equal to number",+      "selector": "$[?@.a>=10]",+      "document": [+        {+          "a": 1,+          "d": "e"+        },+        {+          "a": 10,+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        },+        {+          "a": 20,+          "d": "f"+        }+      ],+      "result": [+        {+          "a": 10,+          "d": "e"+        },+        {+          "a": 20,+          "d": "f"+        }+      ],+      "result_paths": [+        "$[1]",+        "$[3]"+      ]+    },+    {+      "name": "filter, greater than or equal to null",+      "selector": "$[?@.a>=null]",+      "document": [+        {+          "a": null,+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": null,+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ]+    },+    {+      "name": "filter, greater than or equal to true",+      "selector": "$[?@.a>=true]",+      "document": [+        {+          "a": true,+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": true,+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ]+    },+    {+      "name": "filter, greater than or equal to false",+      "selector": "$[?@.a>=false]",+      "document": [+        {+          "a": false,+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": false,+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ]+    },+    {+      "name": "filter, exists and not-equals null, absent from data",+      "selector": "$[?@.a&&@.a!=null]",+      "document": [+        {+          "d": "e"+        },+        {+          "a": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "c",+          "d": "f"+        }+      ],+      "result_paths": [+        "$[1]"+      ]+    },+    {+      "name": "filter, exists and exists, data false",+      "selector": "$[?@.a&&@.b]",+      "document": [+        {+          "a": false,+          "b": false+        },+        {+          "b": false+        },+        {+          "c": false+        }+      ],+      "result": [+        {+          "a": false,+          "b": false+        }+      ],+      "result_paths": [+        "$[0]"+      ]+    },+    {+      "name": "filter, exists or exists, data false",+      "selector": "$[?@.a||@.b]",+      "document": [+        {+          "a": false,+          "b": false+        },+        {+          "b": false+        },+        {+          "c": false+        }+      ],+      "result": [+        {+          "a": false,+          "b": false+        },+        {+          "b": false+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ]+    },+    {+      "name": "filter, and",+      "selector": "$[?@.a>0&&@.a<10]",+      "document": [+        {+          "a": -10,+          "d": "e"+        },+        {+          "a": 5,+          "d": "f"+        },+        {+          "a": 20,+          "d": "f"+        }+      ],+      "result": [+        {+          "a": 5,+          "d": "f"+        }+      ],+      "result_paths": [+        "$[1]"+      ]+    },+    {+      "name": "filter, or",+      "selector": "$[?@.a=='b'||@.a=='d']",+      "document": [+        {+          "a": "a",+          "d": "e"+        },+        {+          "a": "b",+          "d": "f"+        },+        {+          "a": "c",+          "d": "f"+        },+        {+          "a": "d",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "b",+          "d": "f"+        },+        {+          "a": "d",+          "d": "f"+        }+      ],+      "result_paths": [+        "$[1]",+        "$[3]"+      ]+    },+    {+      "name": "filter, not expression",+      "selector": "$[?!(@.a=='b')]",+      "document": [+        {+          "a": "a",+          "d": "e"+        },+        {+          "a": "b",+          "d": "f"+        },+        {+          "a": "d",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "a",+          "d": "e"+        },+        {+          "a": "d",+          "d": "f"+        }+      ],+      "result_paths": [+        "$[0]",+        "$[2]"+      ]+    },+    {+      "name": "filter, not exists",+      "selector": "$[?!@.a]",+      "document": [+        {+          "a": "a",+          "d": "e"+        },+        {+          "d": "f"+        },+        {+          "a": "d",+          "d": "f"+        }+      ],+      "result": [+        {+          "d": "f"+        }+      ],+      "result_paths": [+        "$[1]"+      ]+    },+    {+      "name": "filter, not exists, data null",+      "selector": "$[?!@.a]",+      "document": [+        {+          "a": null,+          "d": "e"+        },+        {+          "d": "f"+        },+        {+          "a": "d",+          "d": "f"+        }+      ],+      "result": [+        {+          "d": "f"+        }+      ],+      "result_paths": [+        "$[1]"+      ]+    },+    {+      "name": "filter, non-singular existence, wildcard",+      "selector": "$[?@.*]",+      "document": [+        1,+        [],+        [+          2+        ],+        {},+        {+          "a": 3+        }+      ],+      "result": [+        [+          2+        ],+        {+          "a": 3+        }+      ],+      "result_paths": [+        "$[2]",+        "$[4]"+      ]+    },+    {+      "name": "filter, non-singular existence, multiple",+      "selector": "$[?@[0, 0, 'a']]",+      "document": [+        1,+        [],+        [+          2+        ],+        [+          2,+          3+        ],+        {+          "a": 3+        },+        {+          "b": 4+        },+        {+          "a": 3,+          "b": 4+        }+      ],+      "result": [+        [+          2+        ],+        [+          2,+          3+        ],+        {+          "a": 3+        },+        {+          "a": 3,+          "b": 4+        }+      ],+      "result_paths": [+        "$[2]",+        "$[3]",+        "$[4]",+        "$[6]"+      ]+    },+    {+      "name": "filter, non-singular existence, slice",+      "selector": "$[?@[0:2]]",+      "document": [+        1,+        [],+        [+          2+        ],+        [+          2,+          3,+          4+        ],+        {},+        {+          "a": 3+        }+      ],+      "result": [+        [+          2+        ],+        [+          2,+          3,+          4+        ]+      ],+      "result_paths": [+        "$[2]",+        "$[3]"+      ]+    },+    {+      "name": "filter, non-singular existence, negated",+      "selector": "$[?!@.*]",+      "document": [+        1,+        [],+        [+          2+        ],+        {},+        {+          "a": 3+        }+      ],+      "result": [+        1,+        [],+        {}+      ],+      "result_paths": [+        "$[0]",+        "$[1]",+        "$[3]"+      ]+    },+    {+      "name": "filter, non-singular query in comparison, slice",+      "selector": "$[?@[0:0]==0]",+      "invalid_selector": true+    },+    {+      "name": "filter, non-singular query in comparison, all children",+      "selector": "$[?@[*]==0]",+      "invalid_selector": true+    },+    {+      "name": "filter, non-singular query in comparison, descendants",+      "selector": "$[?@..a==0]",+      "invalid_selector": true+    },+    {+      "name": "filter, non-singular query in comparison, combined",+      "selector": "$[?@.a[*].a==0]",+      "invalid_selector": true+    },+    {+      "name": "filter, nested",+      "selector": "$[?@[?@>1]]",+      "document": [+        [+          0+        ],+        [+          0,+          1+        ],+        [+          0,+          1,+          2+        ],+        [+          42+        ]+      ],+      "result": [+        [+          0,+          1,+          2+        ],+        [+          42+        ]+      ],+      "result_paths": [+        "$[2]",+        "$[3]"+      ]+    },+    {+      "name": "filter, name segment on primitive, selects nothing",+      "selector": "$[?@.a == 1]",+      "document": {+        "a": 1+      },+      "result": [],+      "result_paths": []+    },+    {+      "name": "filter, name segment on array, selects nothing",+      "selector": "$[?@['0'] == 5]",+      "document": [+        [+          5,+          6+        ]+      ],+      "result": [],+      "result_paths": []+    },+    {+      "name": "filter, index segment on object, selects nothing",+      "selector": "$[?@[0] == 5]",+      "document": [+        {+          "0": 5+        }+      ],+      "result": [],+      "result_paths": []+    },+    {+      "name": "filter, followed by name selector",+      "selector": "$[?@.a==1].b.x",+      "document": [+        {+          "a": 1,+          "b": {+            "x": 2+          }+        }+      ],+      "result": [+        2+      ],+      "result_paths": [+        "$[0]['b']['x']"+      ]+    },+    {+      "name": "filter, followed by child segment that selects multiple elements",+      "selector": "$[?@.z=='_']['x','y']",+      "document": [+        {+          "x": 1,+          "y": null,+          "z": "_"+        }+      ],+      "result": [+        1,+        null+      ],+      "result_paths": [+        "$[0]['x']",+        "$[0]['y']"+      ]+    },+    {+      "name": "filter, relative non-singular query, index, equal",+      "selector": "$[?(@[0, 0]==42)]",+      "invalid_selector": true,+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "filter, relative non-singular query, index, not equal",+      "selector": "$[?(@[0, 0]!=42)]",+      "invalid_selector": true,+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "filter, relative non-singular query, index, less-or-equal",+      "selector": "$[?(@[0, 0]<=42)]",+      "invalid_selector": true,+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "filter, relative non-singular query, name, equal",+      "selector": "$[?(@['a', 'a']==42)]",+      "invalid_selector": true,+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "filter, relative non-singular query, name, not equal",+      "selector": "$[?(@['a', 'a']!=42)]",+      "invalid_selector": true,+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "filter, relative non-singular query, name, less-or-equal",+      "selector": "$[?(@['a', 'a']<=42)]",+      "invalid_selector": true,+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "filter, relative non-singular query, combined, equal",+      "selector": "$[?(@[0, '0']==42)]",+      "invalid_selector": true,+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "filter, relative non-singular query, combined, not equal",+      "selector": "$[?(@[0, '0']!=42)]",+      "invalid_selector": true,+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "filter, relative non-singular query, combined, less-or-equal",+      "selector": "$[?(@[0, '0']<=42)]",+      "invalid_selector": true,+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "filter, relative non-singular query, wildcard, equal",+      "selector": "$[?(@.*==42)]",+      "invalid_selector": true+    },+    {+      "name": "filter, relative non-singular query, wildcard, not equal",+      "selector": "$[?(@.*!=42)]",+      "invalid_selector": true+    },+    {+      "name": "filter, relative non-singular query, wildcard, less-or-equal",+      "selector": "$[?(@.*<=42)]",+      "invalid_selector": true+    },+    {+      "name": "filter, relative non-singular query, slice, equal",+      "selector": "$[?(@[0:0]==42)]",+      "invalid_selector": true+    },+    {+      "name": "filter, relative non-singular query, slice, not equal",+      "selector": "$[?(@[0:0]!=42)]",+      "invalid_selector": true+    },+    {+      "name": "filter, relative non-singular query, slice, less-or-equal",+      "selector": "$[?(@[0:0]<=42)]",+      "invalid_selector": true+    },+    {+      "name": "filter, absolute non-singular query, index, equal",+      "selector": "$[?($[0, 0]==42)]",+      "invalid_selector": true,+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "filter, absolute non-singular query, index, not equal",+      "selector": "$[?($[0, 0]!=42)]",+      "invalid_selector": true,+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "filter, absolute non-singular query, index, less-or-equal",+      "selector": "$[?($[0, 0]<=42)]",+      "invalid_selector": true,+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "filter, absolute non-singular query, name, equal",+      "selector": "$[?($['a', 'a']==42)]",+      "invalid_selector": true,+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "filter, absolute non-singular query, name, not equal",+      "selector": "$[?($['a', 'a']!=42)]",+      "invalid_selector": true,+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "filter, absolute non-singular query, name, less-or-equal",+      "selector": "$[?($['a', 'a']<=42)]",+      "invalid_selector": true,+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "filter, absolute non-singular query, combined, equal",+      "selector": "$[?($[0, '0']==42)]",+      "invalid_selector": true,+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "filter, absolute non-singular query, combined, not equal",+      "selector": "$[?($[0, '0']!=42)]",+      "invalid_selector": true,+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "filter, absolute non-singular query, combined, less-or-equal",+      "selector": "$[?($[0, '0']<=42)]",+      "invalid_selector": true,+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "filter, absolute non-singular query, wildcard, equal",+      "selector": "$[?($.*==42)]",+      "invalid_selector": true+    },+    {+      "name": "filter, absolute non-singular query, wildcard, not equal",+      "selector": "$[?($.*!=42)]",+      "invalid_selector": true+    },+    {+      "name": "filter, absolute non-singular query, wildcard, less-or-equal",+      "selector": "$[?($.*<=42)]",+      "invalid_selector": true+    },+    {+      "name": "filter, absolute non-singular query, slice, equal",+      "selector": "$[?($[0:0]==42)]",+      "invalid_selector": true+    },+    {+      "name": "filter, absolute non-singular query, slice, not equal",+      "selector": "$[?($[0:0]!=42)]",+      "invalid_selector": true+    },+    {+      "name": "filter, absolute non-singular query, slice, less-or-equal",+      "selector": "$[?($[0:0]<=42)]",+      "invalid_selector": true+    },+    {+      "name": "filter, multiple selectors",+      "selector": "$[?@.a,?@.b]",+      "document": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "b": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "b": "c",+          "d": "f"+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ]+    },+    {+      "name": "filter, multiple selectors, comparison",+      "selector": "$[?@.a=='b',?@.b=='x']",+      "document": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "b": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "b",+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ]+    },+    {+      "name": "filter, multiple selectors, overlapping",+      "selector": "$[?@.a,?@.d]",+      "document": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "b": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "a": "b",+          "d": "e"+        },+        {+          "b": "c",+          "d": "f"+        }+      ],+      "result_paths": [+        "$[0]",+        "$[0]",+        "$[1]"+      ]+    },+    {+      "name": "filter, multiple selectors, filter and index",+      "selector": "$[?@.a,1]",+      "document": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "b": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "b": "c",+          "d": "f"+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ]+    },+    {+      "name": "filter, multiple selectors, filter and wildcard",+      "selector": "$[?@.a,*]",+      "document": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "b": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "a": "b",+          "d": "e"+        },+        {+          "b": "c",+          "d": "f"+        }+      ],+      "result_paths": [+        "$[0]",+        "$[0]",+        "$[1]"+      ]+    },+    {+      "name": "filter, multiple selectors, filter and slice",+      "selector": "$[?@.a,1:]",+      "document": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "b": "c",+          "d": "f"+        },+        {+          "g": "h"+        }+      ],+      "result": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "b": "c",+          "d": "f"+        },+        {+          "g": "h"+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]",+        "$[2]"+      ]+    },+    {+      "name": "filter, multiple selectors, comparison filter, index and slice",+      "selector": "$[1, ?@.a=='b', 1:]",+      "document": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "b": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "b": "c",+          "d": "f"+        },+        {+          "a": "b",+          "d": "e"+        },+        {+          "b": "c",+          "d": "f"+        }+      ],+      "result_paths": [+        "$[1]",+        "$[0]",+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "filter, equals number, zero and negative zero",+      "selector": "$[?@.a==0]",+      "document": [+        {+          "a": 0,+          "d": "e"+        },+        {+          "a": 0.1,+          "d": "f"+        },+        {+          "a": "0",+          "d": "g"+        }+      ],+      "result": [+        {+          "a": 0,+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ]+    },+    {+      "name": "filter, equals number, negative zero and zero",+      "selector": "$[?@.a==-0]",+      "document": [+        {+          "a": 0,+          "d": "e"+        },+        {+          "a": 0.1,+          "d": "f"+        },+        {+          "a": "0",+          "d": "g"+        }+      ],+      "result": [+        {+          "a": 0,+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ]+    },+    {+      "name": "filter, equals number, with and without decimal fraction",+      "selector": "$[?@.a==1.0]",+      "document": [+        {+          "a": 1,+          "d": "e"+        },+        {+          "a": 2,+          "d": "f"+        },+        {+          "a": "1",+          "d": "g"+        }+      ],+      "result": [+        {+          "a": 1,+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ]+    },+    {+      "name": "filter, equals number, exponent",+      "selector": "$[?@.a==1e2]",+      "document": [+        {+          "a": 100,+          "d": "e"+        },+        {+          "a": 100.1,+          "d": "f"+        },+        {+          "a": "100",+          "d": "g"+        }+      ],+      "result": [+        {+          "a": 100,+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ]+    },+    {+      "name": "filter, equals number, exponent upper e",+      "selector": "$[?@.a==1E2]",+      "document": [+        {+          "a": 100,+          "d": "e"+        },+        {+          "a": 100.1,+          "d": "f"+        },+        {+          "a": "100",+          "d": "g"+        }+      ],+      "result": [+        {+          "a": 100,+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ]+    },+    {+      "name": "filter, equals number, positive exponent",+      "selector": "$[?@.a==1e+2]",+      "document": [+        {+          "a": 100,+          "d": "e"+        },+        {+          "a": 100.1,+          "d": "f"+        },+        {+          "a": "100",+          "d": "g"+        }+      ],+      "result": [+        {+          "a": 100,+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ]+    },+    {+      "name": "filter, equals number, negative exponent",+      "selector": "$[?@.a==1e-2]",+      "document": [+        {+          "a": 0.01,+          "d": "e"+        },+        {+          "a": 0.02,+          "d": "f"+        },+        {+          "a": "0.01",+          "d": "g"+        }+      ],+      "result": [+        {+          "a": 0.01,+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ]+    },+    {+      "name": "filter, equals number, exponent 0",+      "selector": "$[?@.a==1e0]",+      "document": [+        {+          "a": 1,+          "d": "e"+        },+        {+          "a": 2,+          "d": "f"+        },+        {+          "a": "1",+          "d": "g"+        }+      ],+      "result": [+        {+          "a": 1,+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ]+    },+    {+      "name": "filter, equals number, exponent -0",+      "selector": "$[?@.a==1e-0]",+      "document": [+        {+          "a": 1,+          "d": "e"+        },+        {+          "a": 2,+          "d": "f"+        },+        {+          "a": "1",+          "d": "g"+        }+      ],+      "result": [+        {+          "a": 1,+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ]+    },+    {+      "name": "filter, equals number, exponent +0",+      "selector": "$[?@.a==1e+0]",+      "document": [+        {+          "a": 1,+          "d": "e"+        },+        {+          "a": 2,+          "d": "f"+        },+        {+          "a": "1",+          "d": "g"+        }+      ],+      "result": [+        {+          "a": 1,+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ]+    },+    {+      "name": "filter, equals number, exponent leading -0",+      "selector": "$[?@.a==1e-02]",+      "document": [+        {+          "a": 0.01,+          "d": "e"+        },+        {+          "a": 0.02,+          "d": "f"+        },+        {+          "a": "0.01",+          "d": "g"+        }+      ],+      "result": [+        {+          "a": 0.01,+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ]+    },+    {+      "name": "filter, equals number, exponent +00",+      "selector": "$[?@.a==1e+00]",+      "document": [+        {+          "a": 1,+          "d": "e"+        },+        {+          "a": 2,+          "d": "f"+        },+        {+          "a": "1",+          "d": "g"+        }+      ],+      "result": [+        {+          "a": 1,+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ]+    },+    {+      "name": "filter, equals number, decimal fraction",+      "selector": "$[?@.a==1.1]",+      "document": [+        {+          "a": 1.1,+          "d": "e"+        },+        {+          "a": 1,+          "d": "f"+        },+        {+          "a": "1.1",+          "d": "g"+        }+      ],+      "result": [+        {+          "a": 1.1,+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ]+    },+    {+      "name": "filter, equals number, decimal fraction, trailing 0",+      "selector": "$[?@.a==1.10]",+      "document": [+        {+          "a": 1.1,+          "d": "e"+        },+        {+          "a": 1,+          "d": "f"+        },+        {+          "a": "1.1",+          "d": "g"+        }+      ],+      "result": [+        {+          "a": 1.1,+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ]+    },+    {+      "name": "filter, equals number, decimal fraction, exponent",+      "selector": "$[?@.a==1.1e2]",+      "document": [+        {+          "a": 110,+          "d": "e"+        },+        {+          "a": 110.1,+          "d": "f"+        },+        {+          "a": "110",+          "d": "g"+        }+      ],+      "result": [+        {+          "a": 110,+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ]+    },+    {+      "name": "filter, equals number, decimal fraction, positive exponent",+      "selector": "$[?@.a==1.1e+2]",+      "document": [+        {+          "a": 110,+          "d": "e"+        },+        {+          "a": 110.1,+          "d": "f"+        },+        {+          "a": "110",+          "d": "g"+        }+      ],+      "result": [+        {+          "a": 110,+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ]+    },+    {+      "name": "filter, equals number, decimal fraction, negative exponent",+      "selector": "$[?@.a==1.1e-2]",+      "document": [+        {+          "a": 0.011,+          "d": "e"+        },+        {+          "a": 0.012,+          "d": "f"+        },+        {+          "a": "0.011",+          "d": "g"+        }+      ],+      "result": [+        {+          "a": 0.011,+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ]+    },+    {+      "name": "filter, equals number, invalid plus",+      "selector": "$[?@.a==+1]",+      "invalid_selector": true+    },+    {+      "name": "filter, equals number, invalid minus space",+      "selector": "$[?@.a==- 1]",+      "invalid_selector": true+    },+    {+      "name": "filter, equals number, invalid double minus",+      "selector": "$[?@.a==--1]",+      "invalid_selector": true+    },+    {+      "name": "filter, equals number, invalid no int digit",+      "selector": "$[?@.a==.1]",+      "invalid_selector": true+    },+    {+      "name": "filter, equals number, invalid minus no int digit",+      "selector": "$[?@.a==-.1]",+      "invalid_selector": true+    },+    {+      "name": "filter, equals number, invalid 00",+      "selector": "$[?@.a==00]",+      "invalid_selector": true+    },+    {+      "name": "filter, equals number, invalid leading 0",+      "selector": "$[?@.a==01]",+      "invalid_selector": true+    },+    {+      "name": "filter, equals number, invalid no fractional digit",+      "selector": "$[?@.a==1.]",+      "invalid_selector": true+    },+    {+      "name": "filter, equals number, invalid middle minus",+      "selector": "$[?@.a==1.-1]",+      "invalid_selector": true+    },+    {+      "name": "filter, equals number, invalid no fractional digit e",+      "selector": "$[?@.a==1.e1]",+      "invalid_selector": true+    },+    {+      "name": "filter, equals number, invalid no e digit",+      "selector": "$[?@.a==1e]",+      "invalid_selector": true+    },+    {+      "name": "filter, equals number, invalid no e digit minus",+      "selector": "$[?@.a==1e-]",+      "invalid_selector": true+    },+    {+      "name": "filter, equals number, invalid double e",+      "selector": "$[?@.a==1eE1]",+      "invalid_selector": true+    },+    {+      "name": "filter, equals number, invalid e digit double minus",+      "selector": "$[?@.a==1e--1]",+      "invalid_selector": true+    },+    {+      "name": "filter, equals number, invalid e digit plus minus",+      "selector": "$[?@.a==1e+-1]",+      "invalid_selector": true+    },+    {+      "name": "filter, equals number, invalid e decimal",+      "selector": "$[?@.a==1e2.3]",+      "invalid_selector": true+    },+    {+      "name": "filter, equals number, invalid multi e",+      "selector": "$[?@.a==1e2e3]",+      "invalid_selector": true+    },+    {+      "name": "filter, equals, special nothing",+      "selector": "$.values[?length(@.a) == value($..c)]",+      "document": {+        "c": "cd",+        "values": [+          {+            "a": "ab"+          },+          {+            "c": "d"+          },+          {+            "a": null+          }+        ]+      },+      "result": [+        {+          "c": "d"+        },+        {+          "a": null+        }+      ],+      "result_paths": [+        "$['values'][1]",+        "$['values'][2]"+      ],+      "tags": [+        "function"+      ]+    },+    {+      "name": "filter, equals, empty node list and empty node list",+      "selector": "$[?@.a == @.b]",+      "document": [+        {+          "a": 1+        },+        {+          "b": 2+        },+        {+          "c": 3+        }+      ],+      "result": [+        {+          "c": 3+        }+      ],+      "result_paths": [+        "$[2]"+      ]+    },+    {+      "name": "filter, equals, empty node list and special nothing",+      "selector": "$[?@.a == length(@.b)]",+      "document": [+        {+          "a": 1+        },+        {+          "b": 2+        },+        {+          "c": 3+        }+      ],+      "result": [+        {+          "b": 2+        },+        {+          "c": 3+        }+      ],+      "result_paths": [+        "$[1]",+        "$[2]"+      ],+      "tags": [+        "function",+        "whitespace"+      ]+    },+    {+      "name": "filter, object data",+      "selector": "$[?@<3]",+      "document": {+        "a": 1,+        "b": 2,+        "c": 3+      },+      "results": [+        [+          1,+          2+        ],+        [+          2,+          1+        ]+      ],+      "results_paths": [+        [+          "$['a']",+          "$['b']"+        ],+        [+          "$['b']",+          "$['a']"+        ]+      ]+    },+    {+      "name": "filter, and binds more tightly than or",+      "selector": "$[?@.a || @.b && @.c]",+      "document": [+        {+          "a": 1+        },+        {+          "b": 2,+          "c": 3+        },+        {+          "c": 3+        },+        {+          "b": 2+        },+        {+          "a": 1,+          "b": 2,+          "c": 3+        }+      ],+      "result": [+        {+          "a": 1+        },+        {+          "b": 2,+          "c": 3+        },+        {+          "a": 1,+          "b": 2,+          "c": 3+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]",+        "$[4]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "filter, left to right evaluation",+      "selector": "$[?@.a && @.b || @.c]",+      "document": [+        {+          "a": 1+        },+        {+          "b": 2+        },+        {+          "a": 1,+          "b": 2+        },+        {+          "a": 1,+          "c": 3+        },+        {+          "b": 1,+          "c": 3+        },+        {+          "c": 3+        },+        {+          "a": 1,+          "b": 2,+          "c": 3+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 2+        },+        {+          "a": 1,+          "c": 3+        },+        {+          "b": 1,+          "c": 3+        },+        {+          "c": 3+        },+        {+          "a": 1,+          "b": 2,+          "c": 3+        }+      ],+      "result_paths": [+        "$[2]",+        "$[3]",+        "$[4]",+        "$[5]",+        "$[6]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "filter, group terms, left",+      "selector": "$[?(@.a || @.b) && @.c]",+      "document": [+        {+          "a": 1,+          "b": 2+        },+        {+          "a": 1,+          "c": 3+        },+        {+          "b": 2,+          "c": 3+        },+        {+          "a": 1+        },+        {+          "b": 2+        },+        {+          "c": 3+        },+        {+          "a": 1,+          "b": 2,+          "c": 3+        }+      ],+      "result": [+        {+          "a": 1,+          "c": 3+        },+        {+          "b": 2,+          "c": 3+        },+        {+          "a": 1,+          "b": 2,+          "c": 3+        }+      ],+      "result_paths": [+        "$[1]",+        "$[2]",+        "$[6]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "filter, group terms, right",+      "selector": "$[?@.a && (@.b || @.c)]",+      "document": [+        {+          "a": 1+        },+        {+          "a": 1,+          "b": 2+        },+        {+          "a": 1,+          "c": 2+        },+        {+          "b": 2+        },+        {+          "c": 2+        },+        {+          "a": 1,+          "b": 2,+          "c": 3+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 2+        },+        {+          "a": 1,+          "c": 2+        },+        {+          "a": 1,+          "b": 2,+          "c": 3+        }+      ],+      "result_paths": [+        "$[1]",+        "$[2]",+        "$[5]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "filter, string literal, single quote in double quotes",+      "selector": "$[?@ == \"quoted' literal\"]",+      "document": [+        "quoted' literal",+        "a",+        "quoted\\' literal"+      ],+      "result": [+        "quoted' literal"+      ],+      "result_paths": [+        "$[0]"+      ]+    },+    {+      "name": "filter, string literal, double quote in single quotes",+      "selector": "$[?@ == 'quoted\" literal']",+      "document": [+        "quoted\" literal",+        "a",+        "quoted\\\" literal",+        "'quoted\" literal'"+      ],+      "result": [+        "quoted\" literal"+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "filter, string literal, escaped single quote in single quotes",+      "selector": "$[?@ == 'quoted\\' literal']",+      "document": [+        "quoted' literal",+        "a",+        "quoted\\' literal",+        "'quoted\" literal'"+      ],+      "result": [+        "quoted' literal"+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "filter, string literal, escaped double quote in double quotes",+      "selector": "$[?@ == \"quoted\\\" literal\"]",+      "document": [+        "quoted\" literal",+        "a",+        "quoted\\\" literal",+        "'quoted\" literal'"+      ],+      "result": [+        "quoted\" literal"+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "filter, literal true must be compared",+      "selector": "$[?true]",+      "invalid_selector": true+    },+    {+      "name": "filter, literal false must be compared",+      "selector": "$[?false]",+      "invalid_selector": true+    },+    {+      "name": "filter, literal string must be compared",+      "selector": "$[?'abc']",+      "invalid_selector": true+    },+    {+      "name": "filter, literal int must be compared",+      "selector": "$[?2]",+      "invalid_selector": true+    },+    {+      "name": "filter, literal float must be compared",+      "selector": "$[?2.2]",+      "invalid_selector": true+    },+    {+      "name": "filter, literal null must be compared",+      "selector": "$[?null]",+      "invalid_selector": true+    },+    {+      "name": "filter, and, literals must be compared",+      "selector": "$[?true && false]",+      "invalid_selector": true,+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "filter, or, literals must be compared",+      "selector": "$[?true || false]",+      "invalid_selector": true,+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "filter, and, right hand literal must be compared",+      "selector": "$[?true == false && false]",+      "invalid_selector": true,+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "filter, or, right hand literal must be compared",+      "selector": "$[?true == false || false]",+      "invalid_selector": true,+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "filter, and, left hand literal must be compared",+      "selector": "$[?false && true == false]",+      "invalid_selector": true,+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "filter, or, left hand literal must be compared",+      "selector": "$[?false || true == false]",+      "invalid_selector": true,+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "filter, true, incorrectly capitalized",+      "selector": "$[?@==True]",+      "invalid_selector": true,+      "tags": [+        "case"+      ]+    },+    {+      "name": "filter, false, incorrectly capitalized",+      "selector": "$[?@==False]",+      "invalid_selector": true,+      "tags": [+        "case"+      ]+    },+    {+      "name": "filter, null, incorrectly capitalized",+      "selector": "$[?@==Null]",+      "invalid_selector": true,+      "tags": [+        "case"+      ]+    },+    {+      "name": "index selector, first element",+      "selector": "$[0]",+      "document": [+        "first",+        "second"+      ],+      "result": [+        "first"+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "index"+      ]+    },+    {+      "name": "index selector, second element",+      "selector": "$[1]",+      "document": [+        "first",+        "second"+      ],+      "result": [+        "second"+      ],+      "result_paths": [+        "$[1]"+      ],+      "tags": [+        "index"+      ]+    },+    {+      "name": "index selector, out of bound",+      "selector": "$[2]",+      "document": [+        "first",+        "second"+      ],+      "result": [],+      "result_paths": [],+      "tags": [+        "boundary",+        "index"+      ]+    },+    {+      "name": "index selector, min exact index",+      "selector": "$[-9007199254740991]",+      "document": [+        "first",+        "second"+      ],+      "result": [],+      "result_paths": [],+      "tags": [+        "boundary",+        "index"+      ]+    },+    {+      "name": "index selector, max exact index",+      "selector": "$[9007199254740991]",+      "document": [+        "first",+        "second"+      ],+      "result": [],+      "result_paths": [],+      "tags": [+        "boundary",+        "index"+      ]+    },+    {+      "name": "index selector, min exact index - 1",+      "selector": "$[-9007199254740992]",+      "invalid_selector": true,+      "tags": [+        "boundary",+        "index"+      ]+    },+    {+      "name": "index selector, max exact index + 1",+      "selector": "$[9007199254740992]",+      "invalid_selector": true,+      "tags": [+        "boundary",+        "index"+      ]+    },+    {+      "name": "index selector, overflowing index",+      "selector": "$[231584178474632390847141970017375815706539969331281128078915168015826259279872]",+      "invalid_selector": true,+      "tags": [+        "boundary",+        "index"+      ]+    },+    {+      "name": "index selector, not actually an index, overflowing index leads into general text",+      "selector": "$[231584178474632390847141970017375815706539969331281128078915168SomeRandomText]",+      "invalid_selector": true,+      "tags": [+        "index"+      ]+    },+    {+      "name": "index selector, negative",+      "selector": "$[-1]",+      "document": [+        "first",+        "second"+      ],+      "result": [+        "second"+      ],+      "result_paths": [+        "$[1]"+      ],+      "tags": [+        "index"+      ]+    },+    {+      "name": "index selector, more negative",+      "selector": "$[-2]",+      "document": [+        "first",+        "second"+      ],+      "result": [+        "first"+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "index"+      ]+    },+    {+      "name": "index selector, negative out of bound",+      "selector": "$[-3]",+      "document": [+        "first",+        "second"+      ],+      "result": [],+      "result_paths": [],+      "tags": [+        "boundary",+        "index"+      ]+    },+    {+      "name": "index selector, on object",+      "selector": "$[0]",+      "document": {+        "foo": 1+      },+      "result": [],+      "result_paths": [],+      "tags": [+        "index"+      ]+    },+    {+      "name": "index selector, leading 0",+      "selector": "$[01]",+      "invalid_selector": true,+      "tags": [+        "index"+      ]+    },+    {+      "name": "index selector, decimal",+      "selector": "$[1.0]",+      "invalid_selector": true,+      "tags": [+        "index"+      ]+    },+    {+      "name": "index selector, plus",+      "selector": "$[+1]",+      "invalid_selector": true,+      "tags": [+        "index"+      ]+    },+    {+      "name": "index selector, minus space",+      "selector": "$[- 1]",+      "invalid_selector": true,+      "tags": [+        "index",+        "whitespace"+      ]+    },+    {+      "name": "index selector, -0",+      "selector": "$[-0]",+      "invalid_selector": true,+      "tags": [+        "index"+      ]+    },+    {+      "name": "index selector, leading -0",+      "selector": "$[-01]",+      "invalid_selector": true,+      "tags": [+        "index"+      ]+    },+    {+      "name": "name selector, double quotes",+      "selector": "$[\"a\"]",+      "document": {+        "a": "A",+        "b": "B"+      },+      "result": [+        "A"+      ],+      "result_paths": [+        "$['a']"+      ]+    },+    {+      "name": "name selector, double quotes, absent data",+      "selector": "$[\"c\"]",+      "document": {+        "a": "A",+        "b": "B"+      },+      "result": [],+      "result_paths": []+    },+    {+      "name": "name selector, double quotes, array data",+      "selector": "$[\"a\"]",+      "document": [+        "first",+        "second"+      ],+      "result": [],+      "result_paths": []+    },+    {+      "name": "name selector, name, double quotes, contains single quote",+      "selector": "$[\"a'\"]",+      "document": {+        "a'": "A",+        "b": "B"+      },+      "result": [+        "A"+      ],+      "result_paths": [+        "$['a\\'']"+      ]+    },+    {+      "name": "name selector, name, double quotes, nested",+      "selector": "$[\"a\"][\"b\"][\"c\"]",+      "document": {+        "a": {+          "b": {+            "c": "C"+          }+        }+      },+      "result": [+        "C"+      ],+      "result_paths": [+        "$['a']['b']['c']"+      ]+    },+    {+      "name": "name selector, double quotes, embedded U+0000",+      "selector": "$[\"\u0000\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, embedded U+0001",+      "selector": "$[\"\u0001\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, embedded U+0002",+      "selector": "$[\"\u0002\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, embedded U+0003",+      "selector": "$[\"\u0003\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, embedded U+0004",+      "selector": "$[\"\u0004\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, embedded U+0005",+      "selector": "$[\"\u0005\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, embedded U+0006",+      "selector": "$[\"\u0006\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, embedded U+0007",+      "selector": "$[\"\u0007\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, embedded U+0008",+      "selector": "$[\"\b\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, embedded U+0009",+      "selector": "$[\"\t\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, embedded U+000A",+      "selector": "$[\"\n\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, embedded U+000B",+      "selector": "$[\"\u000b\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, embedded U+000C",+      "selector": "$[\"\f\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, embedded U+000D",+      "selector": "$[\"\r\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, embedded U+000E",+      "selector": "$[\"\u000e\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, embedded U+000F",+      "selector": "$[\"\u000f\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, embedded U+0010",+      "selector": "$[\"\u0010\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, embedded U+0011",+      "selector": "$[\"\u0011\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, embedded U+0012",+      "selector": "$[\"\u0012\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, embedded U+0013",+      "selector": "$[\"\u0013\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, embedded U+0014",+      "selector": "$[\"\u0014\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, embedded U+0015",+      "selector": "$[\"\u0015\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, embedded U+0016",+      "selector": "$[\"\u0016\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, embedded U+0017",+      "selector": "$[\"\u0017\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, embedded U+0018",+      "selector": "$[\"\u0018\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, embedded U+0019",+      "selector": "$[\"\u0019\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, embedded U+001A",+      "selector": "$[\"\u001a\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, embedded U+001B",+      "selector": "$[\"\u001b\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, embedded U+001C",+      "selector": "$[\"\u001c\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, embedded U+001D",+      "selector": "$[\"\u001d\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, embedded U+001E",+      "selector": "$[\"\u001e\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, embedded U+001F",+      "selector": "$[\"\u001f\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, embedded U+0020",+      "selector": "$[\" \"]",+      "document": {+        " ": "A"+      },+      "result": [+        "A"+      ],+      "result_paths": [+        "$[' ']"+      ],+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, embedded U+007F",+      "selector": "$[\"\"]",+      "document": {+        "": "A"+      },+      "result": [+        "A"+      ],+      "result_paths": [+        "$['']"+      ],+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, supplementary plane character",+      "selector": "$[\"𝄞\"]",+      "document": {+        "𝄞": "A"+      },+      "result": [+        "A"+      ],+      "result_paths": [+        "$['𝄞']"+      ],+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, escaped double quote",+      "selector": "$[\"\\\"\"]",+      "document": {+        "\"": "A"+      },+      "result": [+        "A"+      ],+      "result_paths": [+        "$['\"']"+      ]+    },+    {+      "name": "name selector, double quotes, escaped reverse solidus",+      "selector": "$[\"\\\\\"]",+      "document": {+        "\\": "A"+      },+      "result": [+        "A"+      ],+      "result_paths": [+        "$['\\\\']"+      ]+    },+    {+      "name": "name selector, double quotes, escaped solidus",+      "selector": "$[\"\\/\"]",+      "document": {+        "/": "A"+      },+      "result": [+        "A"+      ],+      "result_paths": [+        "$['/']"+      ]+    },+    {+      "name": "name selector, double quotes, escaped backspace",+      "selector": "$[\"\\b\"]",+      "document": {+        "\b": "A"+      },+      "result": [+        "A"+      ],+      "result_paths": [+        "$['\\b']"+      ]+    },+    {+      "name": "name selector, double quotes, escaped form feed",+      "selector": "$[\"\\f\"]",+      "document": {+        "\f": "A"+      },+      "result": [+        "A"+      ],+      "result_paths": [+        "$['\\f']"+      ]+    },+    {+      "name": "name selector, double quotes, escaped line feed",+      "selector": "$[\"\\n\"]",+      "document": {+        "\n": "A"+      },+      "result": [+        "A"+      ],+      "result_paths": [+        "$['\\n']"+      ]+    },+    {+      "name": "name selector, double quotes, escaped carriage return",+      "selector": "$[\"\\r\"]",+      "document": {+        "\r": "A"+      },+      "result": [+        "A"+      ],+      "result_paths": [+        "$['\\r']"+      ]+    },+    {+      "name": "name selector, double quotes, escaped tab",+      "selector": "$[\"\\t\"]",+      "document": {+        "\t": "A"+      },+      "result": [+        "A"+      ],+      "result_paths": [+        "$['\\t']"+      ]+    },+    {+      "name": "name selector, double quotes, escaped ☺, upper case hex",+      "selector": "$[\"\\u263A\"]",+      "document": {+        "☺": "A"+      },+      "result": [+        "A"+      ],+      "result_paths": [+        "$['☺']"+      ],+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, escaped ☺, lower case hex",+      "selector": "$[\"\\u263a\"]",+      "document": {+        "☺": "A"+      },+      "result": [+        "A"+      ],+      "result_paths": [+        "$['☺']"+      ],+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, surrogate pair 𝄞",+      "selector": "$[\"\\uD834\\uDD1E\"]",+      "document": {+        "𝄞": "A"+      },+      "result": [+        "A"+      ],+      "result_paths": [+        "$['𝄞']"+      ],+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, surrogate pair 😀",+      "selector": "$[\"\\uD83D\\uDE00\"]",+      "document": {+        "😀": "A"+      },+      "result": [+        "A"+      ],+      "result_paths": [+        "$['😀']"+      ],+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, before high surrogates",+      "selector": "$[\"\\uD7FF\\uD7FF\"]",+      "document": {+        "퟿퟿": "A"+      },+      "result": [+        "A"+      ],+      "result_paths": [+        "$['퟿퟿']"+      ],+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, after low surrogates",+      "selector": "$[\"\\uE000\\uE000\"]",+      "document": {+        "": "A"+      },+      "result": [+        "A"+      ],+      "result_paths": [+        "$['']"+      ],+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, invalid escaped single quote",+      "selector": "$[\"\\'\"]",+      "invalid_selector": true+    },+    {+      "name": "name selector, double quotes, embedded double quote",+      "selector": "$[\"\"\"]",+      "invalid_selector": true+    },+    {+      "name": "name selector, double quotes, incomplete escape",+      "selector": "$[\"\\\"]",+      "invalid_selector": true+    },+    {+      "name": "name selector, double quotes, escape at end of line",+      "selector": "$[\"\\\n\"]",+      "invalid_selector": true+    },+    {+      "name": "name selector, double quotes, question mark escape",+      "selector": "$[\"\\?\"]",+      "invalid_selector": true+    },+    {+      "name": "name selector, double quotes, bell escape",+      "selector": "$[\"\\a\"]",+      "invalid_selector": true+    },+    {+      "name": "name selector, double quotes, vertical tab escape",+      "selector": "$[\"\\v\"]",+      "invalid_selector": true+    },+    {+      "name": "name selector, double quotes, 0 escape",+      "selector": "$[\"\\0\"]",+      "invalid_selector": true+    },+    {+      "name": "name selector, double quotes, x escape",+      "selector": "$[\"\\x12\"]",+      "invalid_selector": true+    },+    {+      "name": "name selector, double quotes, n escape",+      "selector": "$[\"\\N{LATIN CAPITAL LETTER A}\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, unicode escape no hex",+      "selector": "$[\"\\u\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, unicode escape too few hex",+      "selector": "$[\"\\u123\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, unicode escape upper u",+      "selector": "$[\"\\U1234\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, unicode escape upper u long",+      "selector": "$[\"\\U0010FFFF\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, unicode escape plus",+      "selector": "$[\"\\u+1234\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, unicode escape brackets",+      "selector": "$[\"\\u{1234}\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, unicode escape brackets long",+      "selector": "$[\"\\u{10ffff}\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, single high surrogate",+      "selector": "$[\"\\uD800\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, single low surrogate",+      "selector": "$[\"\\uDC00\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, high high surrogate",+      "selector": "$[\"\\uD800\\uD800\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, low low surrogate",+      "selector": "$[\"\\uDC00\\uDC00\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, surrogate non-surrogate",+      "selector": "$[\"\\uD800\\u1234\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, non-surrogate surrogate",+      "selector": "$[\"\\u1234\\uDC00\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, surrogate supplementary",+      "selector": "$[\"\\uD800𝄞\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, supplementary surrogate",+      "selector": "$[\"𝄞\\uDC00\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, double quotes, surrogate incomplete low",+      "selector": "$[\"\\uD800\\uDC0\"]",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, single quotes",+      "selector": "$['a']",+      "document": {+        "a": "A",+        "b": "B"+      },+      "result": [+        "A"+      ],+      "result_paths": [+        "$['a']"+      ]+    },+    {+      "name": "name selector, single quotes, absent data",+      "selector": "$['c']",+      "document": {+        "a": "A",+        "b": "B"+      },+      "result": [],+      "result_paths": []+    },+    {+      "name": "name selector, single quotes, array data",+      "selector": "$['a']",+      "document": [+        "first",+        "second"+      ],+      "result": [],+      "result_paths": []+    },+    {+      "name": "name selector, single quotes, embedded U+0000",+      "selector": "$['\u0000']",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, single quotes, embedded U+0001",+      "selector": "$['\u0001']",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, single quotes, embedded U+0002",+      "selector": "$['\u0002']",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, single quotes, embedded U+0003",+      "selector": "$['\u0003']",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, single quotes, embedded U+0004",+      "selector": "$['\u0004']",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, single quotes, embedded U+0005",+      "selector": "$['\u0005']",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, single quotes, embedded U+0006",+      "selector": "$['\u0006']",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, single quotes, embedded U+0007",+      "selector": "$['\u0007']",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, single quotes, embedded U+0008",+      "selector": "$['\b']",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, single quotes, embedded U+0009",+      "selector": "$['\t']",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, single quotes, embedded U+000A",+      "selector": "$['\n']",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, single quotes, embedded U+000B",+      "selector": "$['\u000b']",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, single quotes, embedded U+000C",+      "selector": "$['\f']",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, single quotes, embedded U+000D",+      "selector": "$['\r']",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, single quotes, embedded U+000E",+      "selector": "$['\u000e']",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, single quotes, embedded U+000F",+      "selector": "$['\u000f']",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, single quotes, embedded U+0010",+      "selector": "$['\u0010']",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, single quotes, embedded U+0011",+      "selector": "$['\u0011']",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, single quotes, embedded U+0012",+      "selector": "$['\u0012']",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, single quotes, embedded U+0013",+      "selector": "$['\u0013']",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, single quotes, embedded U+0014",+      "selector": "$['\u0014']",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, single quotes, embedded U+0015",+      "selector": "$['\u0015']",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, single quotes, embedded U+0016",+      "selector": "$['\u0016']",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, single quotes, embedded U+0017",+      "selector": "$['\u0017']",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, single quotes, embedded U+0018",+      "selector": "$['\u0018']",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, single quotes, embedded U+0019",+      "selector": "$['\u0019']",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, single quotes, embedded U+001A",+      "selector": "$['\u001a']",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, single quotes, embedded U+001B",+      "selector": "$['\u001b']",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, single quotes, embedded U+001C",+      "selector": "$['\u001c']",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, single quotes, embedded U+001D",+      "selector": "$['\u001d']",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, single quotes, embedded U+001E",+      "selector": "$['\u001e']",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, single quotes, embedded U+001F",+      "selector": "$['\u001f']",+      "invalid_selector": true,+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, single quotes, embedded U+0020",+      "selector": "$[' ']",+      "document": {+        " ": "A"+      },+      "result": [+        "A"+      ],+      "result_paths": [+        "$[' ']"+      ],+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, single quotes, escaped single quote",+      "selector": "$['\\'']",+      "document": {+        "'": "A"+      },+      "result": [+        "A"+      ],+      "result_paths": [+        "$['\\'']"+      ]+    },+    {+      "name": "name selector, single quotes, escaped reverse solidus",+      "selector": "$['\\\\']",+      "document": {+        "\\": "A"+      },+      "result": [+        "A"+      ],+      "result_paths": [+        "$['\\\\']"+      ]+    },+    {+      "name": "name selector, single quotes, escaped solidus",+      "selector": "$['\\/']",+      "document": {+        "/": "A"+      },+      "result": [+        "A"+      ],+      "result_paths": [+        "$['/']"+      ],+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, single quotes, escaped backspace",+      "selector": "$['\\b']",+      "document": {+        "\b": "A"+      },+      "result": [+        "A"+      ],+      "result_paths": [+        "$['\\b']"+      ]+    },+    {+      "name": "name selector, single quotes, escaped form feed",+      "selector": "$['\\f']",+      "document": {+        "\f": "A"+      },+      "result": [+        "A"+      ],+      "result_paths": [+        "$['\\f']"+      ]+    },+    {+      "name": "name selector, single quotes, escaped line feed",+      "selector": "$['\\n']",+      "document": {+        "\n": "A"+      },+      "result": [+        "A"+      ],+      "result_paths": [+        "$['\\n']"+      ]+    },+    {+      "name": "name selector, single quotes, escaped carriage return",+      "selector": "$['\\r']",+      "document": {+        "\r": "A"+      },+      "result": [+        "A"+      ],+      "result_paths": [+        "$['\\r']"+      ]+    },+    {+      "name": "name selector, single quotes, escaped tab",+      "selector": "$['\\t']",+      "document": {+        "\t": "A"+      },+      "result": [+        "A"+      ],+      "result_paths": [+        "$['\\t']"+      ]+    },+    {+      "name": "name selector, single quotes, escaped ☺, upper case hex",+      "selector": "$['\\u263A']",+      "document": {+        "☺": "A"+      },+      "result": [+        "A"+      ],+      "result_paths": [+        "$['☺']"+      ],+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, single quotes, escaped ☺, lower case hex",+      "selector": "$['\\u263a']",+      "document": {+        "☺": "A"+      },+      "result": [+        "A"+      ],+      "result_paths": [+        "$['☺']"+      ],+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, single quotes, surrogate pair 𝄞",+      "selector": "$['\\uD834\\uDD1E']",+      "document": {+        "𝄞": "A"+      },+      "result": [+        "A"+      ],+      "result_paths": [+        "$['𝄞']"+      ],+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, single quotes, surrogate pair 😀",+      "selector": "$['\\uD83D\\uDE00']",+      "document": {+        "😀": "A"+      },+      "result": [+        "A"+      ],+      "result_paths": [+        "$['😀']"+      ],+      "tags": [+        "unicode"+      ]+    },+    {+      "name": "name selector, single quotes, invalid escaped double quote",+      "selector": "$['\\\"']",+      "invalid_selector": true+    },+    {+      "name": "name selector, single quotes, embedded single quote",+      "selector": "$[''']",+      "invalid_selector": true+    },+    {+      "name": "name selector, single quotes, incomplete escape",+      "selector": "$['\\']",+      "invalid_selector": true+    },+    {+      "name": "name selector, double quotes, empty",+      "selector": "$[\"\"]",+      "document": {+        "a": "A",+        "b": "B",+        "": "C"+      },+      "result": [+        "C"+      ],+      "result_paths": [+        "$['']"+      ]+    },+    {+      "name": "name selector, single quotes, empty",+      "selector": "$['']",+      "document": {+        "a": "A",+        "b": "B",+        "": "C"+      },+      "result": [+        "C"+      ],+      "result_paths": [+        "$['']"+      ]+    },+    {+      "name": "slice selector, slice selector",+      "selector": "$[1:3]",+      "document": [+        0,+        1,+        2,+        3,+        4,+        5,+        6,+        7,+        8,+        9+      ],+      "result": [+        1,+        2+      ],+      "result_paths": [+        "$[1]",+        "$[2]"+      ],+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, slice selector with step",+      "selector": "$[1:6:2]",+      "document": [+        0,+        1,+        2,+        3,+        4,+        5,+        6,+        7,+        8,+        9+      ],+      "result": [+        1,+        3,+        5+      ],+      "result_paths": [+        "$[1]",+        "$[3]",+        "$[5]"+      ],+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, slice selector with everything omitted, short form",+      "selector": "$[:]",+      "document": [+        0,+        1,+        2,+        3+      ],+      "result": [+        0,+        1,+        2,+        3+      ],+      "result_paths": [+        "$[0]",+        "$[1]",+        "$[2]",+        "$[3]"+      ],+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, slice selector with everything omitted, long form",+      "selector": "$[::]",+      "document": [+        0,+        1,+        2,+        3+      ],+      "result": [+        0,+        1,+        2,+        3+      ],+      "result_paths": [+        "$[0]",+        "$[1]",+        "$[2]",+        "$[3]"+      ],+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, slice selector with start omitted",+      "selector": "$[:2]",+      "document": [+        0,+        1,+        2,+        3,+        4,+        5,+        6,+        7,+        8,+        9+      ],+      "result": [+        0,+        1+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ],+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, slice selector with start and end omitted",+      "selector": "$[::2]",+      "document": [+        0,+        1,+        2,+        3,+        4,+        5,+        6,+        7,+        8,+        9+      ],+      "result": [+        0,+        2,+        4,+        6,+        8+      ],+      "result_paths": [+        "$[0]",+        "$[2]",+        "$[4]",+        "$[6]",+        "$[8]"+      ],+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, negative step with default start and end",+      "selector": "$[::-1]",+      "document": [+        0,+        1,+        2,+        3+      ],+      "result": [+        3,+        2,+        1,+        0+      ],+      "result_paths": [+        "$[3]",+        "$[2]",+        "$[1]",+        "$[0]"+      ],+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, negative step with default start",+      "selector": "$[:0:-1]",+      "document": [+        0,+        1,+        2,+        3+      ],+      "result": [+        3,+        2,+        1+      ],+      "result_paths": [+        "$[3]",+        "$[2]",+        "$[1]"+      ],+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, negative step with default end",+      "selector": "$[2::-1]",+      "document": [+        0,+        1,+        2,+        3+      ],+      "result": [+        2,+        1,+        0+      ],+      "result_paths": [+        "$[2]",+        "$[1]",+        "$[0]"+      ],+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, larger negative step",+      "selector": "$[::-2]",+      "document": [+        0,+        1,+        2,+        3+      ],+      "result": [+        3,+        1+      ],+      "result_paths": [+        "$[3]",+        "$[1]"+      ],+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, negative range with default step",+      "selector": "$[-1:-3]",+      "document": [+        0,+        1,+        2,+        3,+        4,+        5,+        6,+        7,+        8,+        9+      ],+      "result": [],+      "result_paths": [],+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, negative range with negative step",+      "selector": "$[-1:-3:-1]",+      "document": [+        0,+        1,+        2,+        3,+        4,+        5,+        6,+        7,+        8,+        9+      ],+      "result": [+        9,+        8+      ],+      "result_paths": [+        "$[9]",+        "$[8]"+      ],+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, negative range with larger negative step",+      "selector": "$[-1:-6:-2]",+      "document": [+        0,+        1,+        2,+        3,+        4,+        5,+        6,+        7,+        8,+        9+      ],+      "result": [+        9,+        7,+        5+      ],+      "result_paths": [+        "$[9]",+        "$[7]",+        "$[5]"+      ],+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, larger negative range with larger negative step",+      "selector": "$[-1:-7:-2]",+      "document": [+        0,+        1,+        2,+        3,+        4,+        5,+        6,+        7,+        8,+        9+      ],+      "result": [+        9,+        7,+        5+      ],+      "result_paths": [+        "$[9]",+        "$[7]",+        "$[5]"+      ],+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, negative from, positive to",+      "selector": "$[-5:7]",+      "document": [+        0,+        1,+        2,+        3,+        4,+        5,+        6,+        7,+        8,+        9+      ],+      "result": [+        5,+        6+      ],+      "result_paths": [+        "$[5]",+        "$[6]"+      ],+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, negative from",+      "selector": "$[-2:]",+      "document": [+        0,+        1,+        2,+        3,+        4,+        5,+        6,+        7,+        8,+        9+      ],+      "result": [+        8,+        9+      ],+      "result_paths": [+        "$[8]",+        "$[9]"+      ],+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, positive from, negative to",+      "selector": "$[1:-1]",+      "document": [+        0,+        1,+        2,+        3,+        4,+        5,+        6,+        7,+        8,+        9+      ],+      "result": [+        1,+        2,+        3,+        4,+        5,+        6,+        7,+        8+      ],+      "result_paths": [+        "$[1]",+        "$[2]",+        "$[3]",+        "$[4]",+        "$[5]",+        "$[6]",+        "$[7]",+        "$[8]"+      ],+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, negative from, positive to, negative step",+      "selector": "$[-1:1:-1]",+      "document": [+        0,+        1,+        2,+        3,+        4,+        5,+        6,+        7,+        8,+        9+      ],+      "result": [+        9,+        8,+        7,+        6,+        5,+        4,+        3,+        2+      ],+      "result_paths": [+        "$[9]",+        "$[8]",+        "$[7]",+        "$[6]",+        "$[5]",+        "$[4]",+        "$[3]",+        "$[2]"+      ],+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, positive from, negative to, negative step",+      "selector": "$[7:-5:-1]",+      "document": [+        0,+        1,+        2,+        3,+        4,+        5,+        6,+        7,+        8,+        9+      ],+      "result": [+        7,+        6+      ],+      "result_paths": [+        "$[7]",+        "$[6]"+      ],+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, in serial, on nested array",+      "selector": "$[1:3][1:2]",+      "document": [+        [+          "a",+          "b",+          "c"+        ],+        [+          "d",+          "e",+          "f"+        ],+        [+          "g",+          "h",+          "i"+        ]+      ],+      "result": [+        "e",+        "h"+      ],+      "result_paths": [+        "$[1][1]",+        "$[2][1]"+      ],+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, in serial, on flat array",+      "selector": "$[1:3][::]",+      "document": [+        0,+        1,+        2,+        3,+        4,+        5+      ],+      "result": [],+      "result_paths": [],+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, negative from, negative to, positive step",+      "selector": "$[-5:-2]",+      "document": [+        0,+        1,+        2,+        3,+        4,+        5,+        6,+        7,+        8,+        9+      ],+      "result": [+        5,+        6,+        7+      ],+      "result_paths": [+        "$[5]",+        "$[6]",+        "$[7]"+      ],+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, too many colons",+      "selector": "$[1:2:3:4]",+      "invalid_selector": true,+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, non-integer array index",+      "selector": "$[1:2:a]",+      "invalid_selector": true,+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, zero step",+      "selector": "$[1:2:0]",+      "document": [+        0,+        1,+        2,+        3,+        4,+        5,+        6,+        7,+        8,+        9+      ],+      "result": [],+      "result_paths": [],+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, empty range",+      "selector": "$[2:2]",+      "document": [+        0,+        1,+        2,+        3,+        4,+        5,+        6,+        7,+        8,+        9+      ],+      "result": [],+      "result_paths": [],+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, slice selector with everything omitted with empty array",+      "selector": "$[:]",+      "document": [],+      "result": [],+      "result_paths": [],+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, negative step with empty array",+      "selector": "$[::-1]",+      "document": [],+      "result": [],+      "result_paths": [],+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, maximal range with positive step",+      "selector": "$[0:10]",+      "document": [+        0,+        1,+        2,+        3,+        4,+        5,+        6,+        7,+        8,+        9+      ],+      "result": [+        0,+        1,+        2,+        3,+        4,+        5,+        6,+        7,+        8,+        9+      ],+      "result_paths": [+        "$[0]",+        "$[1]",+        "$[2]",+        "$[3]",+        "$[4]",+        "$[5]",+        "$[6]",+        "$[7]",+        "$[8]",+        "$[9]"+      ],+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, maximal range with negative step",+      "selector": "$[9:0:-1]",+      "document": [+        0,+        1,+        2,+        3,+        4,+        5,+        6,+        7,+        8,+        9+      ],+      "result": [+        9,+        8,+        7,+        6,+        5,+        4,+        3,+        2,+        1+      ],+      "result_paths": [+        "$[9]",+        "$[8]",+        "$[7]",+        "$[6]",+        "$[5]",+        "$[4]",+        "$[3]",+        "$[2]",+        "$[1]"+      ],+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, excessively large to value",+      "selector": "$[2:113667776004]",+      "document": [+        0,+        1,+        2,+        3,+        4,+        5,+        6,+        7,+        8,+        9+      ],+      "result": [+        2,+        3,+        4,+        5,+        6,+        7,+        8,+        9+      ],+      "result_paths": [+        "$[2]",+        "$[3]",+        "$[4]",+        "$[5]",+        "$[6]",+        "$[7]",+        "$[8]",+        "$[9]"+      ],+      "tags": [+        "boundary",+        "slice"+      ]+    },+    {+      "name": "slice selector, excessively small from value",+      "selector": "$[-113667776004:1]",+      "document": [+        0,+        1,+        2,+        3,+        4,+        5,+        6,+        7,+        8,+        9+      ],+      "result": [+        0+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "boundary",+        "slice"+      ]+    },+    {+      "name": "slice selector, excessively large from value with negative step",+      "selector": "$[113667776004:0:-1]",+      "document": [+        0,+        1,+        2,+        3,+        4,+        5,+        6,+        7,+        8,+        9+      ],+      "result": [+        9,+        8,+        7,+        6,+        5,+        4,+        3,+        2,+        1+      ],+      "result_paths": [+        "$[9]",+        "$[8]",+        "$[7]",+        "$[6]",+        "$[5]",+        "$[4]",+        "$[3]",+        "$[2]",+        "$[1]"+      ],+      "tags": [+        "boundary",+        "slice"+      ]+    },+    {+      "name": "slice selector, excessively small to value with negative step",+      "selector": "$[3:-113667776004:-1]",+      "document": [+        0,+        1,+        2,+        3,+        4,+        5,+        6,+        7,+        8,+        9+      ],+      "result": [+        3,+        2,+        1,+        0+      ],+      "result_paths": [+        "$[3]",+        "$[2]",+        "$[1]",+        "$[0]"+      ],+      "tags": [+        "boundary",+        "slice"+      ]+    },+    {+      "name": "slice selector, excessively large step",+      "selector": "$[1:10:113667776004]",+      "document": [+        0,+        1,+        2,+        3,+        4,+        5,+        6,+        7,+        8,+        9+      ],+      "result": [+        1+      ],+      "result_paths": [+        "$[1]"+      ],+      "tags": [+        "boundary",+        "slice"+      ]+    },+    {+      "name": "slice selector, excessively small step",+      "selector": "$[-1:-10:-113667776004]",+      "document": [+        0,+        1,+        2,+        3,+        4,+        5,+        6,+        7,+        8,+        9+      ],+      "result": [+        9+      ],+      "result_paths": [+        "$[9]"+      ],+      "tags": [+        "boundary",+        "slice"+      ]+    },+    {+      "name": "slice selector, start, min exact",+      "selector": "$[-9007199254740991::]",+      "document": [],+      "result": [],+      "result_paths": [],+      "tags": [+        "boundary",+        "slice"+      ]+    },+    {+      "name": "slice selector, start, max exact",+      "selector": "$[9007199254740991::]",+      "document": [],+      "result": [],+      "result_paths": [],+      "tags": [+        "boundary",+        "slice"+      ]+    },+    {+      "name": "slice selector, start, min exact - 1",+      "selector": "$[-9007199254740992::]",+      "invalid_selector": true,+      "tags": [+        "boundary",+        "slice"+      ]+    },+    {+      "name": "slice selector, start, max exact + 1",+      "selector": "$[9007199254740992::]",+      "invalid_selector": true,+      "tags": [+        "boundary",+        "slice"+      ]+    },+    {+      "name": "slice selector, end, min exact",+      "selector": "$[:-9007199254740991:]",+      "document": [],+      "result": [],+      "result_paths": [],+      "tags": [+        "boundary",+        "slice"+      ]+    },+    {+      "name": "slice selector, end, max exact",+      "selector": "$[:9007199254740991:]",+      "document": [],+      "result": [],+      "result_paths": [],+      "tags": [+        "boundary",+        "slice"+      ]+    },+    {+      "name": "slice selector, end, min exact - 1",+      "selector": "$[:-9007199254740992:]",+      "invalid_selector": true,+      "tags": [+        "boundary",+        "slice"+      ]+    },+    {+      "name": "slice selector, end, max exact + 1",+      "selector": "$[:9007199254740992:]",+      "invalid_selector": true,+      "tags": [+        "boundary",+        "slice"+      ]+    },+    {+      "name": "slice selector, step, min exact",+      "selector": "$[::-9007199254740991]",+      "document": [],+      "result": [],+      "result_paths": [],+      "tags": [+        "boundary",+        "slice"+      ]+    },+    {+      "name": "slice selector, step, max exact",+      "selector": "$[::9007199254740991]",+      "document": [],+      "result": [],+      "result_paths": [],+      "tags": [+        "boundary",+        "slice"+      ]+    },+    {+      "name": "slice selector, step, min exact - 1",+      "selector": "$[::-9007199254740992]",+      "invalid_selector": true,+      "tags": [+        "boundary",+        "slice"+      ]+    },+    {+      "name": "slice selector, step, max exact + 1",+      "selector": "$[::9007199254740992]",+      "invalid_selector": true,+      "tags": [+        "boundary",+        "slice"+      ]+    },+    {+      "name": "slice selector, overflowing to value",+      "selector": "$[2:231584178474632390847141970017375815706539969331281128078915168015826259279872]",+      "invalid_selector": true,+      "tags": [+        "boundary",+        "slice"+      ]+    },+    {+      "name": "slice selector, underflowing from value",+      "selector": "$[-231584178474632390847141970017375815706539969331281128078915168015826259279872:1]",+      "invalid_selector": true,+      "tags": [+        "boundary",+        "slice"+      ]+    },+    {+      "name": "slice selector, overflowing from value with negative step",+      "selector": "$[231584178474632390847141970017375815706539969331281128078915168015826259279872:0:-1]",+      "invalid_selector": true,+      "tags": [+        "boundary",+        "slice"+      ]+    },+    {+      "name": "slice selector, underflowing to value with negative step",+      "selector": "$[3:-231584178474632390847141970017375815706539969331281128078915168015826259279872:-1]",+      "invalid_selector": true,+      "tags": [+        "boundary",+        "slice"+      ]+    },+    {+      "name": "slice selector, overflowing step",+      "selector": "$[1:10:231584178474632390847141970017375815706539969331281128078915168015826259279872]",+      "invalid_selector": true,+      "tags": [+        "boundary",+        "slice"+      ]+    },+    {+      "name": "slice selector, underflowing step",+      "selector": "$[-1:-10:-231584178474632390847141970017375815706539969331281128078915168015826259279872]",+      "invalid_selector": true,+      "tags": [+        "boundary",+        "slice"+      ]+    },+    {+      "name": "slice selector, start, leading 0",+      "selector": "$[01::]",+      "invalid_selector": true,+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, start, decimal",+      "selector": "$[1.0::]",+      "invalid_selector": true,+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, start, plus",+      "selector": "$[+1::]",+      "invalid_selector": true,+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, start, minus space",+      "selector": "$[- 1::]",+      "invalid_selector": true,+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, start, -0",+      "selector": "$[-0::]",+      "invalid_selector": true,+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, start, leading -0",+      "selector": "$[-01::]",+      "invalid_selector": true,+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, end, leading 0",+      "selector": "$[:01:]",+      "invalid_selector": true,+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, end, decimal",+      "selector": "$[:1.0:]",+      "invalid_selector": true,+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, end, plus",+      "selector": "$[:+1:]",+      "invalid_selector": true,+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, end, minus space",+      "selector": "$[:- 1:]",+      "invalid_selector": true,+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, end, -0",+      "selector": "$[:-0:]",+      "invalid_selector": true,+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, end, leading -0",+      "selector": "$[:-01:]",+      "invalid_selector": true,+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, step, leading 0",+      "selector": "$[::01]",+      "invalid_selector": true,+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, step, decimal",+      "selector": "$[::1.0]",+      "invalid_selector": true,+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, step, plus",+      "selector": "$[::+1]",+      "invalid_selector": true,+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, step, minus space",+      "selector": "$[::- 1]",+      "invalid_selector": true,+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, step, -0",+      "selector": "$[::-0]",+      "invalid_selector": true,+      "tags": [+        "slice"+      ]+    },+    {+      "name": "slice selector, step, leading -0",+      "selector": "$[::-01]",+      "invalid_selector": true,+      "tags": [+        "slice"+      ]+    },+    {+      "name": "functions, count, count function",+      "selector": "$[?count(@..*)>2]",+      "document": [+        {+          "a": [+            1,+            2,+            3+          ]+        },+        {+          "a": [+            1+          ],+          "d": "f"+        },+        {+          "a": 1,+          "d": "f"+        }+      ],+      "result": [+        {+          "a": [+            1,+            2,+            3+          ]+        },+        {+          "a": [+            1+          ],+          "d": "f"+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ],+      "tags": [+        "count",+        "function"+      ]+    },+    {+      "name": "functions, count, single-node arg",+      "selector": "$[?count(@.a)>1]",+      "document": [+        {+          "a": [+            1,+            2,+            3+          ]+        },+        {+          "a": [+            1+          ],+          "d": "f"+        },+        {+          "a": 1,+          "d": "f"+        }+      ],+      "result": [],+      "result_paths": [],+      "tags": [+        "count",+        "function"+      ]+    },+    {+      "name": "functions, count, multiple-selector arg",+      "selector": "$[?count(@['a','d'])>1]",+      "document": [+        {+          "a": [+            1,+            2,+            3+          ]+        },+        {+          "a": [+            1+          ],+          "d": "f"+        },+        {+          "a": 1,+          "d": "f"+        }+      ],+      "result": [+        {+          "a": [+            1+          ],+          "d": "f"+        },+        {+          "a": 1,+          "d": "f"+        }+      ],+      "result_paths": [+        "$[1]",+        "$[2]"+      ],+      "tags": [+        "count",+        "function"+      ]+    },+    {+      "name": "functions, count, non-query arg, number",+      "selector": "$[?count(1)>2]",+      "invalid_selector": true,+      "tags": [+        "count",+        "function"+      ]+    },+    {+      "name": "functions, count, non-query arg, string",+      "selector": "$[?count('string')>2]",+      "invalid_selector": true,+      "tags": [+        "count",+        "function"+      ]+    },+    {+      "name": "functions, count, non-query arg, true",+      "selector": "$[?count(true)>2]",+      "invalid_selector": true,+      "tags": [+        "count",+        "function"+      ]+    },+    {+      "name": "functions, count, non-query arg, false",+      "selector": "$[?count(false)>2]",+      "invalid_selector": true,+      "tags": [+        "count",+        "function"+      ]+    },+    {+      "name": "functions, count, non-query arg, null",+      "selector": "$[?count(null)>2]",+      "invalid_selector": true,+      "tags": [+        "count",+        "function"+      ]+    },+    {+      "name": "functions, count, result must be compared",+      "selector": "$[?count(@..*)]",+      "invalid_selector": true,+      "tags": [+        "count",+        "function"+      ]+    },+    {+      "name": "functions, count, no params",+      "selector": "$[?count()==1]",+      "invalid_selector": true,+      "tags": [+        "count",+        "function"+      ]+    },+    {+      "name": "functions, count, too many params",+      "selector": "$[?count(@.a,@.b)==1]",+      "invalid_selector": true,+      "tags": [+        "count",+        "function"+      ]+    },+    {+      "name": "functions, length, string data",+      "selector": "$[?length(@.a)>=2]",+      "document": [+        {+          "a": "ab"+        },+        {+          "a": "d"+        }+      ],+      "result": [+        {+          "a": "ab"+        }+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "function",+        "length"+      ]+    },+    {+      "name": "functions, length, string data, unicode",+      "selector": "$[?length(@)==2]",+      "document": [+        "☺",+        "☺☺",+        "☺☺☺",+        "ж",+        "жж",+        "жжж",+        "磨",+        "阿美",+        "形声字"+      ],+      "result": [+        "☺☺",+        "жж",+        "阿美"+      ],+      "result_paths": [+        "$[1]",+        "$[4]",+        "$[7]"+      ],+      "tags": [+        "function",+        "length"+      ]+    },+    {+      "name": "functions, length, array data",+      "selector": "$[?length(@.a)>=2]",+      "document": [+        {+          "a": [+            1,+            2,+            3+          ]+        },+        {+          "a": [+            1+          ]+        }+      ],+      "result": [+        {+          "a": [+            1,+            2,+            3+          ]+        }+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "function",+        "length"+      ]+    },+    {+      "name": "functions, length, missing data",+      "selector": "$[?length(@.a)>=2]",+      "document": [+        {+          "d": "f"+        }+      ],+      "result": [],+      "result_paths": [],+      "tags": [+        "function",+        "length"+      ]+    },+    {+      "name": "functions, length, number arg",+      "selector": "$[?length(1)>=2]",+      "document": [+        {+          "d": "f"+        }+      ],+      "result": [],+      "result_paths": [],+      "tags": [+        "function",+        "length"+      ]+    },+    {+      "name": "functions, length, true arg",+      "selector": "$[?length(true)>=2]",+      "document": [+        {+          "d": "f"+        }+      ],+      "result": [],+      "result_paths": [],+      "tags": [+        "function",+        "length"+      ]+    },+    {+      "name": "functions, length, false arg",+      "selector": "$[?length(false)>=2]",+      "document": [+        {+          "d": "f"+        }+      ],+      "result": [],+      "result_paths": [],+      "tags": [+        "function",+        "length"+      ]+    },+    {+      "name": "functions, length, null arg",+      "selector": "$[?length(null)>=2]",+      "document": [+        {+          "d": "f"+        }+      ],+      "result": [],+      "result_paths": [],+      "tags": [+        "function",+        "length"+      ]+    },+    {+      "name": "functions, length, result must be compared",+      "selector": "$[?length(@.a)]",+      "invalid_selector": true,+      "tags": [+        "function",+        "length"+      ]+    },+    {+      "name": "functions, length, no params",+      "selector": "$[?length()==1]",+      "invalid_selector": true,+      "tags": [+        "function",+        "length"+      ]+    },+    {+      "name": "functions, length, too many params",+      "selector": "$[?length(@.a,@.b)==1]",+      "invalid_selector": true,+      "tags": [+        "function",+        "length"+      ]+    },+    {+      "name": "functions, length, non-singular query arg",+      "selector": "$[?length(@.*)<3]",+      "invalid_selector": true,+      "tags": [+        "function",+        "length"+      ]+    },+    {+      "name": "functions, length, arg is a function expression",+      "selector": "$.values[?length(@.a)==length(value($..c))]",+      "document": {+        "c": "cd",+        "values": [+          {+            "a": "ab"+          },+          {+            "a": "d"+          }+        ]+      },+      "result": [+        {+          "a": "ab"+        }+      ],+      "result_paths": [+        "$['values'][0]"+      ],+      "tags": [+        "function",+        "length"+      ]+    },+    {+      "name": "functions, length, arg is special nothing",+      "selector": "$[?length(value(@.a))>0]",+      "document": [+        {+          "a": "ab"+        },+        {+          "c": "d"+        },+        {+          "a": null+        }+      ],+      "result": [+        {+          "a": "ab"+        }+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "function",+        "length"+      ]+    },+    {+      "name": "functions, match, found match",+      "selector": "$[?match(@.a, 'a.*')]",+      "document": [+        {+          "a": "ab"+        }+      ],+      "result": [+        {+          "a": "ab"+        }+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "function",+        "match"+      ]+    },+    {+      "name": "functions, match, double quotes",+      "selector": "$[?match(@.a, \"a.*\")]",+      "document": [+        {+          "a": "ab"+        }+      ],+      "result": [+        {+          "a": "ab"+        }+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "function",+        "match"+      ]+    },+    {+      "name": "functions, match, regex from the document",+      "selector": "$.values[?match(@, $.regex)]",+      "document": {+        "regex": "b.?b",+        "values": [+          "abc",+          "bcd",+          "bab",+          "bba",+          "bbab",+          "b",+          true,+          [],+          {}+        ]+      },+      "result": [+        "bab"+      ],+      "result_paths": [+        "$['values'][2]"+      ],+      "tags": [+        "function",+        "match"+      ]+    },+    {+      "name": "functions, match, don't select match",+      "selector": "$[?!match(@.a, 'a.*')]",+      "document": [+        {+          "a": "ab"+        }+      ],+      "result": [],+      "result_paths": [],+      "tags": [+        "function",+        "match"+      ]+    },+    {+      "name": "functions, match, not a match",+      "selector": "$[?match(@.a, 'a.*')]",+      "document": [+        {+          "a": "bc"+        }+      ],+      "result": [],+      "result_paths": [],+      "tags": [+        "function",+        "match"+      ]+    },+    {+      "name": "functions, match, select non-match",+      "selector": "$[?!match(@.a, 'a.*')]",+      "document": [+        {+          "a": "bc"+        }+      ],+      "result": [+        {+          "a": "bc"+        }+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "function",+        "match"+      ]+    },+    {+      "name": "functions, match, non-string first arg",+      "selector": "$[?match(1, 'a.*')]",+      "document": [+        {+          "a": "bc"+        }+      ],+      "result": [],+      "result_paths": [],+      "tags": [+        "function",+        "match"+      ]+    },+    {+      "name": "functions, match, non-string second arg",+      "selector": "$[?match(@.a, 1)]",+      "document": [+        {+          "a": "bc"+        }+      ],+      "result": [],+      "result_paths": [],+      "tags": [+        "function",+        "match"+      ]+    },+    {+      "name": "functions, match, filter, match function, unicode char class, uppercase",+      "selector": "$[?match(@, '\\\\p{Lu}')]",+      "document": [+        "ж",+        "Ж",+        "1",+        "жЖ",+        true,+        [],+        {}+      ],+      "result": [+        "Ж"+      ],+      "result_paths": [+        "$[1]"+      ],+      "tags": [+        "function",+        "match"+      ]+    },+    {+      "name": "functions, match, filter, match function, unicode char class negated, uppercase",+      "selector": "$[?match(@, '\\\\P{Lu}')]",+      "document": [+        "ж",+        "Ж",+        "1",+        true,+        [],+        {}+      ],+      "result": [+        "ж",+        "1"+      ],+      "result_paths": [+        "$[0]",+        "$[2]"+      ],+      "tags": [+        "function",+        "match"+      ]+    },+    {+      "name": "functions, match, filter, match function, unicode, surrogate pair",+      "selector": "$[?match(@, 'a.b')]",+      "document": [+        "a𐄁b",+        "ab",+        "1",+        true,+        [],+        {}+      ],+      "result": [+        "a𐄁b"+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "function",+        "match"+      ]+    },+    {+      "name": "functions, match, dot matcher on \\u2028",+      "selector": "$[?match(@, '.')]",+      "document": [+        "
",+        "\r",+        "\n",+        true,+        [],+        {}+      ],+      "result": [+        "
"+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "function",+        "match"+      ]+    },+    {+      "name": "functions, match, dot matcher on \\u2029",+      "selector": "$[?match(@, '.')]",+      "document": [+        "
",+        "\r",+        "\n",+        true,+        [],+        {}+      ],+      "result": [+        "
"+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "function",+        "match"+      ]+    },+    {+      "name": "functions, match, result cannot be compared",+      "selector": "$[?match(@.a, 'a.*')==true]",+      "invalid_selector": true,+      "tags": [+        "function",+        "match"+      ]+    },+    {+      "name": "functions, match, too few params",+      "selector": "$[?match(@.a)==1]",+      "invalid_selector": true,+      "tags": [+        "function",+        "match"+      ]+    },+    {+      "name": "functions, match, too many params",+      "selector": "$[?match(@.a,@.b,@.c)==1]",+      "invalid_selector": true,+      "tags": [+        "function",+        "match"+      ]+    },+    {+      "name": "functions, match, arg is a function expression",+      "selector": "$.values[?match(@.a, value($..['regex']))]",+      "document": {+        "regex": "a.*",+        "values": [+          {+            "a": "ab"+          },+          {+            "a": "ba"+          }+        ]+      },+      "result": [+        {+          "a": "ab"+        }+      ],+      "result_paths": [+        "$['values'][0]"+      ],+      "tags": [+        "function",+        "match"+      ]+    },+    {+      "name": "functions, match, dot in character class",+      "selector": "$[?match(@, 'a[.b]c')]",+      "document": [+        "abc",+        "a.c",+        "axc"+      ],+      "result": [+        "abc",+        "a.c"+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ],+      "tags": [+        "function",+        "match"+      ]+    },+    {+      "name": "functions, match, escaped dot",+      "selector": "$[?match(@, 'a\\\\.c')]",+      "document": [+        "abc",+        "a.c",+        "axc"+      ],+      "result": [+        "a.c"+      ],+      "result_paths": [+        "$[1]"+      ],+      "tags": [+        "function",+        "match"+      ]+    },+    {+      "name": "functions, match, escaped backslash before dot",+      "selector": "$[?match(@, 'a\\\\\\\\.c')]",+      "document": [+        "abc",+        "a.c",+        "axc",+        "a\\
c"+      ],+      "result": [+        "a\\
c"+      ],+      "result_paths": [+        "$[3]"+      ],+      "tags": [+        "function",+        "match"+      ]+    },+    {+      "name": "functions, match, escaped left square bracket",+      "selector": "$[?match(@, 'a\\\\[.c')]",+      "document": [+        "abc",+        "a.c",+        "a[
c"+      ],+      "result": [+        "a[
c"+      ],+      "result_paths": [+        "$[2]"+      ],+      "tags": [+        "function",+        "match"+      ]+    },+    {+      "name": "functions, match, escaped right square bracket",+      "selector": "$[?match(@, 'a[\\\\].]c')]",+      "document": [+        "abc",+        "a.c",+        "a
c",+        "a]c"+      ],+      "result": [+        "a.c",+        "a]c"+      ],+      "result_paths": [+        "$[1]",+        "$[3]"+      ],+      "tags": [+        "function",+        "match"+      ]+    },+    {+      "name": "functions, match, explicit caret",+      "selector": "$[?match(@, '^ab.*')]",+      "document": [+        "abc",+        "axc",+        "ab",+        "xab"+      ],+      "result": [+        "abc",+        "ab"+      ],+      "result_paths": [+        "$[0]",+        "$[2]"+      ],+      "tags": [+        "function",+        "match"+      ]+    },+    {+      "name": "functions, match, explicit dollar",+      "selector": "$[?match(@, '.*bc$')]",+      "document": [+        "abc",+        "axc",+        "ab",+        "abcx"+      ],+      "result": [+        "abc"+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "function",+        "match"+      ]+    },+    {+      "name": "functions, search, at the end",+      "selector": "$[?search(@.a, 'a.*')]",+      "document": [+        {+          "a": "the end is ab"+        }+      ],+      "result": [+        {+          "a": "the end is ab"+        }+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "function",+        "search"+      ]+    },+    {+      "name": "functions, search, double quotes",+      "selector": "$[?search(@.a, \"a.*\")]",+      "document": [+        {+          "a": "the end is ab"+        }+      ],+      "result": [+        {+          "a": "the end is ab"+        }+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "function",+        "search"+      ]+    },+    {+      "name": "functions, search, at the start",+      "selector": "$[?search(@.a, 'a.*')]",+      "document": [+        {+          "a": "ab is at the start"+        }+      ],+      "result": [+        {+          "a": "ab is at the start"+        }+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "function",+        "search"+      ]+    },+    {+      "name": "functions, search, in the middle",+      "selector": "$[?search(@.a, 'a.*')]",+      "document": [+        {+          "a": "contains two matches"+        }+      ],+      "result": [+        {+          "a": "contains two matches"+        }+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "function",+        "search"+      ]+    },+    {+      "name": "functions, search, regex from the document",+      "selector": "$.values[?search(@, $.regex)]",+      "document": {+        "regex": "b.?b",+        "values": [+          "abc",+          "bcd",+          "bab",+          "bba",+          "bbab",+          "b",+          true,+          [],+          {}+        ]+      },+      "result": [+        "bab",+        "bba",+        "bbab"+      ],+      "result_paths": [+        "$['values'][2]",+        "$['values'][3]",+        "$['values'][4]"+      ],+      "tags": [+        "function",+        "search"+      ]+    },+    {+      "name": "functions, search, don't select match",+      "selector": "$[?!search(@.a, 'a.*')]",+      "document": [+        {+          "a": "contains two matches"+        }+      ],+      "result": [],+      "result_paths": [],+      "tags": [+        "function",+        "search"+      ]+    },+    {+      "name": "functions, search, not a match",+      "selector": "$[?search(@.a, 'a.*')]",+      "document": [+        {+          "a": "bc"+        }+      ],+      "result": [],+      "result_paths": [],+      "tags": [+        "function",+        "search"+      ]+    },+    {+      "name": "functions, search, select non-match",+      "selector": "$[?!search(@.a, 'a.*')]",+      "document": [+        {+          "a": "bc"+        }+      ],+      "result": [+        {+          "a": "bc"+        }+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "function",+        "search"+      ]+    },+    {+      "name": "functions, search, non-string first arg",+      "selector": "$[?search(1, 'a.*')]",+      "document": [+        {+          "a": "bc"+        }+      ],+      "result": [],+      "result_paths": [],+      "tags": [+        "function",+        "search"+      ]+    },+    {+      "name": "functions, search, non-string second arg",+      "selector": "$[?search(@.a, 1)]",+      "document": [+        {+          "a": "bc"+        }+      ],+      "result": [],+      "result_paths": [],+      "tags": [+        "function",+        "search"+      ]+    },+    {+      "name": "functions, search, filter, search function, unicode char class, uppercase",+      "selector": "$[?search(@, '\\\\p{Lu}')]",+      "document": [+        "ж",+        "Ж",+        "1",+        "жЖ",+        true,+        [],+        {}+      ],+      "result": [+        "Ж",+        "жЖ"+      ],+      "result_paths": [+        "$[1]",+        "$[3]"+      ],+      "tags": [+        "function",+        "search"+      ]+    },+    {+      "name": "functions, search, filter, search function, unicode char class negated, uppercase",+      "selector": "$[?search(@, '\\\\P{Lu}')]",+      "document": [+        "ж",+        "Ж",+        "1",+        true,+        [],+        {}+      ],+      "result": [+        "ж",+        "1"+      ],+      "result_paths": [+        "$[0]",+        "$[2]"+      ],+      "tags": [+        "function",+        "search"+      ]+    },+    {+      "name": "functions, search, filter, search function, unicode, surrogate pair",+      "selector": "$[?search(@, 'a.b')]",+      "document": [+        "a𐄁bc",+        "abc",+        "1",+        true,+        [],+        {}+      ],+      "result": [+        "a𐄁bc"+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "function",+        "search"+      ]+    },+    {+      "name": "functions, search, dot matcher on \\u2028",+      "selector": "$[?search(@, '.')]",+      "document": [+        "
",+        "\r
\n",+        "\r",+        "\n",+        true,+        [],+        {}+      ],+      "result": [+        "
",+        "\r
\n"+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ],+      "tags": [+        "function",+        "search"+      ]+    },+    {+      "name": "functions, search, dot matcher on \\u2029",+      "selector": "$[?search(@, '.')]",+      "document": [+        "
",+        "\r
\n",+        "\r",+        "\n",+        true,+        [],+        {}+      ],+      "result": [+        "
",+        "\r
\n"+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ],+      "tags": [+        "function",+        "search"+      ]+    },+    {+      "name": "functions, search, result cannot be compared",+      "selector": "$[?search(@.a, 'a.*')==true]",+      "invalid_selector": true,+      "tags": [+        "function",+        "search"+      ]+    },+    {+      "name": "functions, search, too few params",+      "selector": "$[?search(@.a)]",+      "invalid_selector": true,+      "tags": [+        "function",+        "search"+      ]+    },+    {+      "name": "functions, search, too many params",+      "selector": "$[?search(@.a,@.b,@.c)]",+      "invalid_selector": true,+      "tags": [+        "function",+        "search"+      ]+    },+    {+      "name": "functions, search, arg is a function expression",+      "selector": "$.values[?search(@, value($..['regex']))]",+      "document": {+        "regex": "b.?b",+        "values": [+          "abc",+          "bcd",+          "bab",+          "bba",+          "bbab",+          "b",+          true,+          [],+          {}+        ]+      },+      "result": [+        "bab",+        "bba",+        "bbab"+      ],+      "result_paths": [+        "$['values'][2]",+        "$['values'][3]",+        "$['values'][4]"+      ],+      "tags": [+        "function",+        "search"+      ]+    },+    {+      "name": "functions, search, dot in character class",+      "selector": "$[?search(@, 'a[.b]c')]",+      "document": [+        "x abc y",+        "x a.c y",+        "x axc y"+      ],+      "result": [+        "x abc y",+        "x a.c y"+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ],+      "tags": [+        "function",+        "search"+      ]+    },+    {+      "name": "functions, search, escaped dot",+      "selector": "$[?search(@, 'a\\\\.c')]",+      "document": [+        "x abc y",+        "x a.c y",+        "x axc y"+      ],+      "result": [+        "x a.c y"+      ],+      "result_paths": [+        "$[1]"+      ],+      "tags": [+        "function",+        "search"+      ]+    },+    {+      "name": "functions, search, escaped backslash before dot",+      "selector": "$[?search(@, 'a\\\\\\\\.c')]",+      "document": [+        "x abc y",+        "x a.c y",+        "x axc y",+        "x a\\
c y"+      ],+      "result": [+        "x a\\
c y"+      ],+      "result_paths": [+        "$[3]"+      ],+      "tags": [+        "function",+        "search"+      ]+    },+    {+      "name": "functions, search, escaped left square bracket",+      "selector": "$[?search(@, 'a\\\\[.c')]",+      "document": [+        "x abc y",+        "x a.c y",+        "x a[
c y"+      ],+      "result": [+        "x a[
c y"+      ],+      "result_paths": [+        "$[2]"+      ],+      "tags": [+        "function",+        "search"+      ]+    },+    {+      "name": "functions, search, escaped right square bracket",+      "selector": "$[?search(@, 'a[\\\\].]c')]",+      "document": [+        "x abc y",+        "x a.c y",+        "x a
c y",+        "x a]c y"+      ],+      "result": [+        "x a.c y",+        "x a]c y"+      ],+      "result_paths": [+        "$[1]",+        "$[3]"+      ],+      "tags": [+        "function",+        "search"+      ]+    },+    {+      "name": "functions, value, single-value nodelist",+      "selector": "$[?value(@.*)==4]",+      "document": [+        [+          4+        ],+        {+          "foo": 4+        },+        [+          5+        ],+        {+          "foo": 5+        },+        4+      ],+      "result": [+        [+          4+        ],+        {+          "foo": 4+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ],+      "tags": [+        "function",+        "value"+      ]+    },+    {+      "name": "functions, value, multi-value nodelist",+      "selector": "$[?value(@.*)==4]",+      "document": [+        [+          4,+          4+        ],+        {+          "foo": 4,+          "bar": 4+        }+      ],+      "result": [],+      "result_paths": [],+      "tags": [+        "function",+        "value"+      ]+    },+    {+      "name": "functions, value, too few params",+      "selector": "$[?value()==4]",+      "invalid_selector": true,+      "tags": [+        "function",+        "value"+      ]+    },+    {+      "name": "functions, value, too many params",+      "selector": "$[?value(@.a,@.b)==4]",+      "invalid_selector": true,+      "tags": [+        "function",+        "value"+      ]+    },+    {+      "name": "functions, value, result must be compared",+      "selector": "$[?value(@.a)]",+      "invalid_selector": true,+      "tags": [+        "function",+        "value"+      ]+    },+    {+      "name": "whitespace, filter, space between question mark and expression",+      "selector": "$[? @.a]",+      "document": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "b": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "b",+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, filter, newline between question mark and expression",+      "selector": "$[?\n@.a]",+      "document": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "b": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "b",+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, filter, tab between question mark and expression",+      "selector": "$[?\t@.a]",+      "document": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "b": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "b",+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, filter, return between question mark and expression",+      "selector": "$[?\r@.a]",+      "document": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "b": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "b",+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, filter, space between question mark and parenthesized expression",+      "selector": "$[? (@.a)]",+      "document": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "b": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "b",+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, filter, newline between question mark and parenthesized expression",+      "selector": "$[?\n(@.a)]",+      "document": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "b": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "b",+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, filter, tab between question mark and parenthesized expression",+      "selector": "$[?\t(@.a)]",+      "document": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "b": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "b",+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, filter, return between question mark and parenthesized expression",+      "selector": "$[?\r(@.a)]",+      "document": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "b": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "b",+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, filter, space between parenthesized expression and bracket",+      "selector": "$[?(@.a) ]",+      "document": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "b": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "b",+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, filter, newline between parenthesized expression and bracket",+      "selector": "$[?(@.a)\n]",+      "document": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "b": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "b",+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, filter, tab between parenthesized expression and bracket",+      "selector": "$[?(@.a)\t]",+      "document": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "b": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "b",+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, filter, return between parenthesized expression and bracket",+      "selector": "$[?(@.a)\r]",+      "document": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "b": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "b",+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, filter, space between bracket and question mark",+      "selector": "$[ ?@.a]",+      "document": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "b": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "b",+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, filter, newline between bracket and question mark",+      "selector": "$[\n?@.a]",+      "document": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "b": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "b",+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, filter, tab between bracket and question mark",+      "selector": "$[\t?@.a]",+      "document": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "b": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "b",+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, filter, return between bracket and question mark",+      "selector": "$[\r?@.a]",+      "document": [+        {+          "a": "b",+          "d": "e"+        },+        {+          "b": "c",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "b",+          "d": "e"+        }+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, functions, space between function name and parenthesis",+      "selector": "$[?count (@.*)==1]",+      "invalid_selector": true,+      "tags": [+        "count",+        "function",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, functions, newline between function name and parenthesis",+      "selector": "$[?count\n(@.*)==1]",+      "invalid_selector": true,+      "tags": [+        "count",+        "function",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, functions, tab between function name and parenthesis",+      "selector": "$[?count\t(@.*)==1]",+      "invalid_selector": true,+      "tags": [+        "count",+        "function",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, functions, return between function name and parenthesis",+      "selector": "$[?count\r(@.*)==1]",+      "invalid_selector": true,+      "tags": [+        "count",+        "function",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, functions, space between parenthesis and arg",+      "selector": "$[?count( @.*)==1]",+      "document": [+        {+          "a": 1+        },+        {+          "b": 2+        },+        {+          "a": 2,+          "b": 1+        }+      ],+      "result": [+        {+          "a": 1+        },+        {+          "b": 2+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ],+      "tags": [+        "count",+        "function",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, functions, newline between parenthesis and arg",+      "selector": "$[?count(\n@.*)==1]",+      "document": [+        {+          "a": 1+        },+        {+          "b": 2+        },+        {+          "a": 2,+          "b": 1+        }+      ],+      "result": [+        {+          "a": 1+        },+        {+          "b": 2+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ],+      "tags": [+        "count",+        "function",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, functions, tab between parenthesis and arg",+      "selector": "$[?count(\t@.*)==1]",+      "document": [+        {+          "a": 1+        },+        {+          "b": 2+        },+        {+          "a": 2,+          "b": 1+        }+      ],+      "result": [+        {+          "a": 1+        },+        {+          "b": 2+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ],+      "tags": [+        "count",+        "function",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, functions, return between parenthesis and arg",+      "selector": "$[?count(\r@.*)==1]",+      "document": [+        {+          "a": 1+        },+        {+          "b": 2+        },+        {+          "a": 2,+          "b": 1+        }+      ],+      "result": [+        {+          "a": 1+        },+        {+          "b": 2+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ],+      "tags": [+        "count",+        "function",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, functions, space between arg and comma",+      "selector": "$[?search(@ ,'[a-z]+')]",+      "document": [+        "foo",+        "123"+      ],+      "result": [+        "foo"+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "function",+        "search",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, functions, newline between arg and comma",+      "selector": "$[?search(@\n,'[a-z]+')]",+      "document": [+        "foo",+        "123"+      ],+      "result": [+        "foo"+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "function",+        "search",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, functions, tab between arg and comma",+      "selector": "$[?search(@\t,'[a-z]+')]",+      "document": [+        "foo",+        "123"+      ],+      "result": [+        "foo"+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "function",+        "search",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, functions, return between arg and comma",+      "selector": "$[?search(@\r,'[a-z]+')]",+      "document": [+        "foo",+        "123"+      ],+      "result": [+        "foo"+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "function",+        "search",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, functions, space between comma and arg",+      "selector": "$[?search(@, '[a-z]+')]",+      "document": [+        "foo",+        "123"+      ],+      "result": [+        "foo"+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "function",+        "search",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, functions, newline between comma and arg",+      "selector": "$[?search(@,\n'[a-z]+')]",+      "document": [+        "foo",+        "123"+      ],+      "result": [+        "foo"+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "function",+        "search",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, functions, tab between comma and arg",+      "selector": "$[?search(@,\t'[a-z]+')]",+      "document": [+        "foo",+        "123"+      ],+      "result": [+        "foo"+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "function",+        "search",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, functions, return between comma and arg",+      "selector": "$[?search(@,\r'[a-z]+')]",+      "document": [+        "foo",+        "123"+      ],+      "result": [+        "foo"+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "function",+        "search",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, functions, space between arg and parenthesis",+      "selector": "$[?count(@.* )==1]",+      "document": [+        {+          "a": 1+        },+        {+          "b": 2+        },+        {+          "a": 2,+          "b": 1+        }+      ],+      "result": [+        {+          "a": 1+        },+        {+          "b": 2+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ],+      "tags": [+        "function",+        "search",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, functions, newline between arg and parenthesis",+      "selector": "$[?count(@.*\n)==1]",+      "document": [+        {+          "a": 1+        },+        {+          "b": 2+        },+        {+          "a": 2,+          "b": 1+        }+      ],+      "result": [+        {+          "a": 1+        },+        {+          "b": 2+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ],+      "tags": [+        "count",+        "function",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, functions, tab between arg and parenthesis",+      "selector": "$[?count(@.*\t)==1]",+      "document": [+        {+          "a": 1+        },+        {+          "b": 2+        },+        {+          "a": 2,+          "b": 1+        }+      ],+      "result": [+        {+          "a": 1+        },+        {+          "b": 2+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ],+      "tags": [+        "count",+        "function",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, functions, return between arg and parenthesis",+      "selector": "$[?count(@.*\r)==1]",+      "document": [+        {+          "a": 1+        },+        {+          "b": 2+        },+        {+          "a": 2,+          "b": 1+        }+      ],+      "result": [+        {+          "a": 1+        },+        {+          "b": 2+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ],+      "tags": [+        "count",+        "function",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, functions, spaces in a relative singular selector",+      "selector": "$[?length(@ .a .b) == 3]",+      "document": [+        {+          "a": {+            "b": "foo"+          }+        },+        {}+      ],+      "result": [+        {+          "a": {+            "b": "foo"+          }+        }+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "function",+        "length",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, functions, newlines in a relative singular selector",+      "selector": "$[?length(@\n.a\n.b) == 3]",+      "document": [+        {+          "a": {+            "b": "foo"+          }+        },+        {}+      ],+      "result": [+        {+          "a": {+            "b": "foo"+          }+        }+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "function",+        "length",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, functions, tabs in a relative singular selector",+      "selector": "$[?length(@\t.a\t.b) == 3]",+      "document": [+        {+          "a": {+            "b": "foo"+          }+        },+        {}+      ],+      "result": [+        {+          "a": {+            "b": "foo"+          }+        }+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "function",+        "length",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, functions, returns in a relative singular selector",+      "selector": "$[?length(@\r.a\r.b) == 3]",+      "document": [+        {+          "a": {+            "b": "foo"+          }+        },+        {}+      ],+      "result": [+        {+          "a": {+            "b": "foo"+          }+        }+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "function",+        "length",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, functions, spaces in an absolute singular selector",+      "selector": "$..[?length(@)==length($ [0] .a)]",+      "document": [+        {+          "a": "foo"+        },+        {}+      ],+      "result": [+        "foo"+      ],+      "result_paths": [+        "$[0]['a']"+      ],+      "tags": [+        "function",+        "length",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, functions, newlines in an absolute singular selector",+      "selector": "$..[?length(@)==length($\n[0]\n.a)]",+      "document": [+        {+          "a": "foo"+        },+        {}+      ],+      "result": [+        "foo"+      ],+      "result_paths": [+        "$[0]['a']"+      ],+      "tags": [+        "function",+        "length",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, functions, tabs in an absolute singular selector",+      "selector": "$..[?length(@)==length($\t[0]\t.a)]",+      "document": [+        {+          "a": "foo"+        },+        {}+      ],+      "result": [+        "foo"+      ],+      "result_paths": [+        "$[0]['a']"+      ],+      "tags": [+        "function",+        "length",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, functions, returns in an absolute singular selector",+      "selector": "$..[?length(@)==length($\r[0]\r.a)]",+      "document": [+        {+          "a": "foo"+        },+        {}+      ],+      "result": [+        "foo"+      ],+      "result_paths": [+        "$[0]['a']"+      ],+      "tags": [+        "function",+        "length",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, space before ||",+      "selector": "$[?@.a ||@.b]",+      "document": [+        {+          "a": 1+        },+        {+          "b": 2+        },+        {+          "c": 3+        }+      ],+      "result": [+        {+          "a": 1+        },+        {+          "b": 2+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, newline before ||",+      "selector": "$[?@.a\n||@.b]",+      "document": [+        {+          "a": 1+        },+        {+          "b": 2+        },+        {+          "c": 3+        }+      ],+      "result": [+        {+          "a": 1+        },+        {+          "b": 2+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, tab before ||",+      "selector": "$[?@.a\t||@.b]",+      "document": [+        {+          "a": 1+        },+        {+          "b": 2+        },+        {+          "c": 3+        }+      ],+      "result": [+        {+          "a": 1+        },+        {+          "b": 2+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, return before ||",+      "selector": "$[?@.a\r||@.b]",+      "document": [+        {+          "a": 1+        },+        {+          "b": 2+        },+        {+          "c": 3+        }+      ],+      "result": [+        {+          "a": 1+        },+        {+          "b": 2+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, space after ||",+      "selector": "$[?@.a|| @.b]",+      "document": [+        {+          "a": 1+        },+        {+          "b": 2+        },+        {+          "c": 3+        }+      ],+      "result": [+        {+          "a": 1+        },+        {+          "b": 2+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, newline after ||",+      "selector": "$[?@.a||\n@.b]",+      "document": [+        {+          "a": 1+        },+        {+          "b": 2+        },+        {+          "c": 3+        }+      ],+      "result": [+        {+          "a": 1+        },+        {+          "b": 2+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, tab after ||",+      "selector": "$[?@.a||\t@.b]",+      "document": [+        {+          "a": 1+        },+        {+          "b": 2+        },+        {+          "c": 3+        }+      ],+      "result": [+        {+          "a": 1+        },+        {+          "b": 2+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, return after ||",+      "selector": "$[?@.a||\r@.b]",+      "document": [+        {+          "a": 1+        },+        {+          "b": 2+        },+        {+          "c": 3+        }+      ],+      "result": [+        {+          "a": 1+        },+        {+          "b": 2+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, space before &&",+      "selector": "$[?@.a &&@.b]",+      "document": [+        {+          "a": 1+        },+        {+          "b": 2+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[2]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, newline before &&",+      "selector": "$[?@.a\n&&@.b]",+      "document": [+        {+          "a": 1+        },+        {+          "b": 2+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[2]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, tab before &&",+      "selector": "$[?@.a\t&&@.b]",+      "document": [+        {+          "a": 1+        },+        {+          "b": 2+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[2]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, return before &&",+      "selector": "$[?@.a\r&&@.b]",+      "document": [+        {+          "a": 1+        },+        {+          "b": 2+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[2]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, space after &&",+      "selector": "$[?@.a&& @.b]",+      "document": [+        {+          "a": 1+        },+        {+          "b": 2+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[2]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, newline after &&",+      "selector": "$[?@.a&& @.b]",+      "document": [+        {+          "a": 1+        },+        {+          "b": 2+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[2]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, tab after &&",+      "selector": "$[?@.a&& @.b]",+      "document": [+        {+          "a": 1+        },+        {+          "b": 2+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[2]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, return after &&",+      "selector": "$[?@.a&& @.b]",+      "document": [+        {+          "a": 1+        },+        {+          "b": 2+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[2]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, space before ==",+      "selector": "$[?@.a ==@.b]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 1+        }+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, newline before ==",+      "selector": "$[?@.a\n==@.b]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 1+        }+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, tab before ==",+      "selector": "$[?@.a\t==@.b]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 1+        }+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, return before ==",+      "selector": "$[?@.a\r==@.b]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 1+        }+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, space after ==",+      "selector": "$[?@.a== @.b]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 1+        }+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, newline after ==",+      "selector": "$[?@.a==\n@.b]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 1+        }+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, tab after ==",+      "selector": "$[?@.a==\t@.b]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 1+        }+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, return after ==",+      "selector": "$[?@.a==\r@.b]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 1+        }+      ],+      "result_paths": [+        "$[0]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, space before !=",+      "selector": "$[?@.a !=@.b]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, newline before !=",+      "selector": "$[?@.a\n!=@.b]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, tab before !=",+      "selector": "$[?@.a\t!=@.b]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, return before !=",+      "selector": "$[?@.a\r!=@.b]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, space after !=",+      "selector": "$[?@.a!= @.b]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, newline after !=",+      "selector": "$[?@.a!=\n@.b]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, tab after !=",+      "selector": "$[?@.a!=\t@.b]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, return after !=",+      "selector": "$[?@.a!=\r@.b]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, space before <",+      "selector": "$[?@.a <@.b]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, newline before <",+      "selector": "$[?@.a\n<@.b]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, tab before <",+      "selector": "$[?@.a\t<@.b]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, return before <",+      "selector": "$[?@.a\r<@.b]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, space after <",+      "selector": "$[?@.a< @.b]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, newline after <",+      "selector": "$[?@.a<\n@.b]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, tab after <",+      "selector": "$[?@.a<\t@.b]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, return after <",+      "selector": "$[?@.a<\r@.b]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, space before >",+      "selector": "$[?@.b >@.a]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, newline before >",+      "selector": "$[?@.b\n>@.a]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, tab before >",+      "selector": "$[?@.b\t>@.a]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, return before >",+      "selector": "$[?@.b\r>@.a]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, space after >",+      "selector": "$[?@.b> @.a]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, newline after >",+      "selector": "$[?@.b>\n@.a]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, tab after >",+      "selector": "$[?@.b>\t@.a]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, return after >",+      "selector": "$[?@.b>\r@.a]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, space before <=",+      "selector": "$[?@.a <=@.b]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        },+        {+          "a": 2,+          "b": 1+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, newline before <=",+      "selector": "$[?@.a\n<=@.b]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        },+        {+          "a": 2,+          "b": 1+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, tab before <=",+      "selector": "$[?@.a\t<=@.b]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        },+        {+          "a": 2,+          "b": 1+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, return before <=",+      "selector": "$[?@.a\r<=@.b]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        },+        {+          "a": 2,+          "b": 1+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, space after <=",+      "selector": "$[?@.a<= @.b]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        },+        {+          "a": 2,+          "b": 1+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, newline after <=",+      "selector": "$[?@.a<=\n@.b]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        },+        {+          "a": 2,+          "b": 1+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, tab after <=",+      "selector": "$[?@.a<=\t@.b]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        },+        {+          "a": 2,+          "b": 1+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, return after <=",+      "selector": "$[?@.a<=\r@.b]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        },+        {+          "a": 2,+          "b": 1+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, space before >=",+      "selector": "$[?@.b >=@.a]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        },+        {+          "a": 2,+          "b": 1+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, newline before >=",+      "selector": "$[?@.b\n>=@.a]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        },+        {+          "a": 2,+          "b": 1+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, tab before >=",+      "selector": "$[?@.b\t>=@.a]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        },+        {+          "a": 2,+          "b": 1+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, return before >=",+      "selector": "$[?@.b\r>=@.a]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        },+        {+          "a": 2,+          "b": 1+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, space after >=",+      "selector": "$[?@.b>= @.a]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        },+        {+          "a": 2,+          "b": 1+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, newline after >=",+      "selector": "$[?@.b>=\n@.a]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        },+        {+          "a": 2,+          "b": 1+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, tab after >=",+      "selector": "$[?@.b>=\t@.a]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        },+        {+          "a": 2,+          "b": 1+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, return after >=",+      "selector": "$[?@.b>=\r@.a]",+      "document": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        },+        {+          "a": 2,+          "b": 1+        }+      ],+      "result": [+        {+          "a": 1,+          "b": 1+        },+        {+          "a": 1,+          "b": 2+        }+      ],+      "result_paths": [+        "$[0]",+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, space between logical not and test expression",+      "selector": "$[?! @.a]",+      "document": [+        {+          "a": "a",+          "d": "e"+        },+        {+          "d": "f"+        },+        {+          "a": "d",+          "d": "f"+        }+      ],+      "result": [+        {+          "d": "f"+        }+      ],+      "result_paths": [+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, newline between logical not and test expression",+      "selector": "$[?!\n@.a]",+      "document": [+        {+          "a": "a",+          "d": "e"+        },+        {+          "d": "f"+        },+        {+          "a": "d",+          "d": "f"+        }+      ],+      "result": [+        {+          "d": "f"+        }+      ],+      "result_paths": [+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, tab between logical not and test expression",+      "selector": "$[?!\t@.a]",+      "document": [+        {+          "a": "a",+          "d": "e"+        },+        {+          "d": "f"+        },+        {+          "a": "d",+          "d": "f"+        }+      ],+      "result": [+        {+          "d": "f"+        }+      ],+      "result_paths": [+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, return between logical not and test expression",+      "selector": "$[?!\r@.a]",+      "document": [+        {+          "a": "a",+          "d": "e"+        },+        {+          "d": "f"+        },+        {+          "a": "d",+          "d": "f"+        }+      ],+      "result": [+        {+          "d": "f"+        }+      ],+      "result_paths": [+        "$[1]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, space between logical not and parenthesized expression",+      "selector": "$[?! (@.a=='b')]",+      "document": [+        {+          "a": "a",+          "d": "e"+        },+        {+          "a": "b",+          "d": "f"+        },+        {+          "a": "d",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "a",+          "d": "e"+        },+        {+          "a": "d",+          "d": "f"+        }+      ],+      "result_paths": [+        "$[0]",+        "$[2]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, newline between logical not and parenthesized expression",+      "selector": "$[?!\n(@.a=='b')]",+      "document": [+        {+          "a": "a",+          "d": "e"+        },+        {+          "a": "b",+          "d": "f"+        },+        {+          "a": "d",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "a",+          "d": "e"+        },+        {+          "a": "d",+          "d": "f"+        }+      ],+      "result_paths": [+        "$[0]",+        "$[2]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, tab between logical not and parenthesized expression",+      "selector": "$[?!\t(@.a=='b')]",+      "document": [+        {+          "a": "a",+          "d": "e"+        },+        {+          "a": "b",+          "d": "f"+        },+        {+          "a": "d",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "a",+          "d": "e"+        },+        {+          "a": "d",+          "d": "f"+        }+      ],+      "result_paths": [+        "$[0]",+        "$[2]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, operators, return between logical not and parenthesized expression",+      "selector": "$[?!\r(@.a=='b')]",+      "document": [+        {+          "a": "a",+          "d": "e"+        },+        {+          "a": "b",+          "d": "f"+        },+        {+          "a": "d",+          "d": "f"+        }+      ],+      "result": [+        {+          "a": "a",+          "d": "e"+        },+        {+          "a": "d",+          "d": "f"+        }+      ],+      "result_paths": [+        "$[0]",+        "$[2]"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, selectors, space between root and bracket",+      "selector": "$ ['a']",+      "document": {+        "a": "ab"+      },+      "result": [+        "ab"+      ],+      "result_paths": [+        "$['a']"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, selectors, newline between root and bracket",+      "selector": "$\n['a']",+      "document": {+        "a": "ab"+      },+      "result": [+        "ab"+      ],+      "result_paths": [+        "$['a']"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, selectors, tab between root and bracket",+      "selector": "$\t['a']",+      "document": {+        "a": "ab"+      },+      "result": [+        "ab"+      ],+      "result_paths": [+        "$['a']"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, selectors, return between root and bracket",+      "selector": "$\r['a']",+      "document": {+        "a": "ab"+      },+      "result": [+        "ab"+      ],+      "result_paths": [+        "$['a']"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, selectors, space between bracket and bracket",+      "selector": "$['a'] ['b']",+      "document": {+        "a": {+          "b": "ab"+        }+      },+      "result": [+        "ab"+      ],+      "result_paths": [+        "$['a']['b']"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, selectors, newline between bracket and bracket",+      "selector": "$['a'] \n['b']",+      "document": {+        "a": {+          "b": "ab"+        }+      },+      "result": [+        "ab"+      ],+      "result_paths": [+        "$['a']['b']"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, selectors, tab between bracket and bracket",+      "selector": "$['a'] \t['b']",+      "document": {+        "a": {+          "b": "ab"+        }+      },+      "result": [+        "ab"+      ],+      "result_paths": [+        "$['a']['b']"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, selectors, return between bracket and bracket",+      "selector": "$['a'] \r['b']",+      "document": {+        "a": {+          "b": "ab"+        }+      },+      "result": [+        "ab"+      ],+      "result_paths": [+        "$['a']['b']"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, selectors, space between root and dot",+      "selector": "$ .a",+      "document": {+        "a": "ab"+      },+      "result": [+        "ab"+      ],+      "result_paths": [+        "$['a']"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, selectors, newline between root and dot",+      "selector": "$\n.a",+      "document": {+        "a": "ab"+      },+      "result": [+        "ab"+      ],+      "result_paths": [+        "$['a']"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, selectors, tab between root and dot",+      "selector": "$\t.a",+      "document": {+        "a": "ab"+      },+      "result": [+        "ab"+      ],+      "result_paths": [+        "$['a']"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, selectors, return between root and dot",+      "selector": "$\r.a",+      "document": {+        "a": "ab"+      },+      "result": [+        "ab"+      ],+      "result_paths": [+        "$['a']"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, selectors, space between dot and name",+      "selector": "$. a",+      "invalid_selector": true,+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, selectors, newline between dot and name",+      "selector": "$.\na",+      "invalid_selector": true,+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, selectors, tab between dot and name",+      "selector": "$.\ta",+      "invalid_selector": true,+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, selectors, return between dot and name",+      "selector": "$.\ra",+      "invalid_selector": true,+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, selectors, space between recursive descent and name",+      "selector": "$.. a",+      "invalid_selector": true,+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, selectors, newline between recursive descent and name",+      "selector": "$..\na",+      "invalid_selector": true,+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, selectors, tab between recursive descent and name",+      "selector": "$..\ta",+      "invalid_selector": true,+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, selectors, return between recursive descent and name",+      "selector": "$..\ra",+      "invalid_selector": true,+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, selectors, space between bracket and selector",+      "selector": "$[ 'a']",+      "document": {+        "a": "ab"+      },+      "result": [+        "ab"+      ],+      "result_paths": [+        "$['a']"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, selectors, newline between bracket and selector",+      "selector": "$[\n'a']",+      "document": {+        "a": "ab"+      },+      "result": [+        "ab"+      ],+      "result_paths": [+        "$['a']"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, selectors, tab between bracket and selector",+      "selector": "$[\t'a']",+      "document": {+        "a": "ab"+      },+      "result": [+        "ab"+      ],+      "result_paths": [+        "$['a']"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, selectors, return between bracket and selector",+      "selector": "$[\r'a']",+      "document": {+        "a": "ab"+      },+      "result": [+        "ab"+      ],+      "result_paths": [+        "$['a']"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, selectors, space between selector and bracket",+      "selector": "$['a' ]",+      "document": {+        "a": "ab"+      },+      "result": [+        "ab"+      ],+      "result_paths": [+        "$['a']"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, selectors, newline between selector and bracket",+      "selector": "$['a'\n]",+      "document": {+        "a": "ab"+      },+      "result": [+        "ab"+      ],+      "result_paths": [+        "$['a']"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, selectors, tab between selector and bracket",+      "selector": "$['a'\t]",+      "document": {+        "a": "ab"+      },+      "result": [+        "ab"+      ],+      "result_paths": [+        "$['a']"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, selectors, return between selector and bracket",+      "selector": "$['a'\r]",+      "document": {+        "a": "ab"+      },+      "result": [+        "ab"+      ],+      "result_paths": [+        "$['a']"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, selectors, space between selector and comma",+      "selector": "$['a' ,'b']",+      "document": {+        "a": "ab",+        "b": "bc"+      },+      "result": [+        "ab",+        "bc"+      ],+      "result_paths": [+        "$['a']",+        "$['b']"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, selectors, newline between selector and comma",+      "selector": "$['a'\n,'b']",+      "document": {+        "a": "ab",+        "b": "bc"+      },+      "result": [+        "ab",+        "bc"+      ],+      "result_paths": [+        "$['a']",+        "$['b']"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, selectors, tab between selector and comma",+      "selector": "$['a'\t,'b']",+      "document": {+        "a": "ab",+        "b": "bc"+      },+      "result": [+        "ab",+        "bc"+      ],+      "result_paths": [+        "$['a']",+        "$['b']"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, selectors, return between selector and comma",+      "selector": "$['a'\r,'b']",+      "document": {+        "a": "ab",+        "b": "bc"+      },+      "result": [+        "ab",+        "bc"+      ],+      "result_paths": [+        "$['a']",+        "$['b']"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, selectors, space between comma and selector",+      "selector": "$['a', 'b']",+      "document": {+        "a": "ab",+        "b": "bc"+      },+      "result": [+        "ab",+        "bc"+      ],+      "result_paths": [+        "$['a']",+        "$['b']"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, selectors, newline between comma and selector",+      "selector": "$['a',\n'b']",+      "document": {+        "a": "ab",+        "b": "bc"+      },+      "result": [+        "ab",+        "bc"+      ],+      "result_paths": [+        "$['a']",+        "$['b']"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, selectors, tab between comma and selector",+      "selector": "$['a',\t'b']",+      "document": {+        "a": "ab",+        "b": "bc"+      },+      "result": [+        "ab",+        "bc"+      ],+      "result_paths": [+        "$['a']",+        "$['b']"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, selectors, return between comma and selector",+      "selector": "$['a',\r'b']",+      "document": {+        "a": "ab",+        "b": "bc"+      },+      "result": [+        "ab",+        "bc"+      ],+      "result_paths": [+        "$['a']",+        "$['b']"+      ],+      "tags": [+        "whitespace"+      ]+    },+    {+      "name": "whitespace, slice, space between start and colon",+      "selector": "$[1 :5:2]",+      "document": [+        1,+        2,+        3,+        4,+        5,+        6+      ],+      "result": [+        2,+        4+      ],+      "result_paths": [+        "$[1]",+        "$[3]"+      ],+      "tags": [+        "index",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, slice, newline between start and colon",+      "selector": "$[1\n:5:2]",+      "document": [+        1,+        2,+        3,+        4,+        5,+        6+      ],+      "result": [+        2,+        4+      ],+      "result_paths": [+        "$[1]",+        "$[3]"+      ],+      "tags": [+        "index",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, slice, tab between start and colon",+      "selector": "$[1\t:5:2]",+      "document": [+        1,+        2,+        3,+        4,+        5,+        6+      ],+      "result": [+        2,+        4+      ],+      "result_paths": [+        "$[1]",+        "$[3]"+      ],+      "tags": [+        "index",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, slice, return between start and colon",+      "selector": "$[1\r:5:2]",+      "document": [+        1,+        2,+        3,+        4,+        5,+        6+      ],+      "result": [+        2,+        4+      ],+      "result_paths": [+        "$[1]",+        "$[3]"+      ],+      "tags": [+        "index",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, slice, space between colon and end",+      "selector": "$[1: 5:2]",+      "document": [+        1,+        2,+        3,+        4,+        5,+        6+      ],+      "result": [+        2,+        4+      ],+      "result_paths": [+        "$[1]",+        "$[3]"+      ],+      "tags": [+        "index",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, slice, newline between colon and end",+      "selector": "$[1:\n5:2]",+      "document": [+        1,+        2,+        3,+        4,+        5,+        6+      ],+      "result": [+        2,+        4+      ],+      "result_paths": [+        "$[1]",+        "$[3]"+      ],+      "tags": [+        "index",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, slice, tab between colon and end",+      "selector": "$[1:\t5:2]",+      "document": [+        1,+        2,+        3,+        4,+        5,+        6+      ],+      "result": [+        2,+        4+      ],+      "result_paths": [+        "$[1]",+        "$[3]"+      ],+      "tags": [+        "index",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, slice, return between colon and end",+      "selector": "$[1:\r5:2]",+      "document": [+        1,+        2,+        3,+        4,+        5,+        6+      ],+      "result": [+        2,+        4+      ],+      "result_paths": [+        "$[1]",+        "$[3]"+      ],+      "tags": [+        "index",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, slice, space between end and colon",+      "selector": "$[1:5 :2]",+      "document": [+        1,+        2,+        3,+        4,+        5,+        6+      ],+      "result": [+        2,+        4+      ],+      "result_paths": [+        "$[1]",+        "$[3]"+      ],+      "tags": [+        "index",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, slice, newline between end and colon",+      "selector": "$[1:5\n:2]",+      "document": [+        1,+        2,+        3,+        4,+        5,+        6+      ],+      "result": [+        2,+        4+      ],+      "result_paths": [+        "$[1]",+        "$[3]"+      ],+      "tags": [+        "index",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, slice, tab between end and colon",+      "selector": "$[1:5\t:2]",+      "document": [+        1,+        2,+        3,+        4,+        5,+        6+      ],+      "result": [+        2,+        4+      ],+      "result_paths": [+        "$[1]",+        "$[3]"+      ],+      "tags": [+        "index",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, slice, return between end and colon",+      "selector": "$[1:5\r:2]",+      "document": [+        1,+        2,+        3,+        4,+        5,+        6+      ],+      "result": [+        2,+        4+      ],+      "result_paths": [+        "$[1]",+        "$[3]"+      ],+      "tags": [+        "index",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, slice, space between colon and step",+      "selector": "$[1:5: 2]",+      "document": [+        1,+        2,+        3,+        4,+        5,+        6+      ],+      "result": [+        2,+        4+      ],+      "result_paths": [+        "$[1]",+        "$[3]"+      ],+      "tags": [+        "index",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, slice, newline between colon and step",+      "selector": "$[1:5:\n2]",+      "document": [+        1,+        2,+        3,+        4,+        5,+        6+      ],+      "result": [+        2,+        4+      ],+      "result_paths": [+        "$[1]",+        "$[3]"+      ],+      "tags": [+        "index",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, slice, tab between colon and step",+      "selector": "$[1:5:\t2]",+      "document": [+        1,+        2,+        3,+        4,+        5,+        6+      ],+      "result": [+        2,+        4+      ],+      "result_paths": [+        "$[1]",+        "$[3]"+      ],+      "tags": [+        "index",+        "whitespace"+      ]+    },+    {+      "name": "whitespace, slice, return between colon and step",+      "selector": "$[1:5:\r2]",+      "document": [+        1,+        2,+        3,+        4,+        5,+        6+      ],+      "result": [+        2,+        4+      ],+      "result_paths": [+        "$[1]",+        "$[3]"+      ],+      "tags": [+        "index",+        "whitespace"+      ]+    }+  ]+}
src/Data/Aeson/JSONPath.hs view
@@ -27,15 +27,16 @@  import qualified Text.ParserCombinators.Parsec as P -import Data.Aeson                   (Value)-import Data.Vector                  (Vector)-import Language.Haskell.TH.Quote    (QuasiQuoter (..))-import Language.Haskell.TH.Syntax   (lift)+import Data.Aeson                  (Value)+import Data.Vector                 (Vector)+import Language.Haskell.TH.Quote   (QuasiQuoter (..))+import Language.Haskell.TH.Syntax  (lift) -import Data.Aeson.JSONPath.Query.Types (Query (..))-import Data.Aeson.JSONPath.Query       (Queryable (..))-import Data.Aeson.JSONPath.Parser      (pQuery)+import Data.Aeson.JSONPath.Parser  (pQuery)+import Data.Aeson.JSONPath.Query   (qQuery, qQueryLocated) +import Data.Aeson.JSONPath.Types+ import Prelude  -- |@@ -85,7 +86,11 @@ -- artist = queryQQ [jsonPath|$.art[ist|] json -- fails at compilation time -- @ queryQQ :: Query -> Value -> Vector Value-queryQQ q root = query' q root root+queryQQ q root = qQuery q QueryState {+    rootVal = root+  , curVal = root+  , executeQuery = qQuery+}  -- | -- Get the location of the returned nodes along with the node@@ -110,7 +115,11 @@ --  ("$[\'title\']",String "Space Oddity")] -- @ queryLocatedQQ :: Query -> Value -> Vector (String, Value)-queryLocatedQQ q root = queryLocated' q root root "$"+queryLocatedQQ q root = qQueryLocated q QueryState {+    rootVal = root+  , curVal = root+  , executeQuery = qQuery+} "$"  -- $use --
src/Data/Aeson/JSONPath/Parser.hs view
@@ -1,375 +1,26 @@ {-# OPTIONS_GHC -Wno-unused-do-bind #-} {- | Module      : Data.Aeson.JSONPath.Parser-Description : Parses the raw query to ADT+Description : JSONPath Query Parser Copyright   : (c) 2024-2025 Taimoor Zaeem License     : MIT Maintainer  : Taimoor Zaeem <mtaimoorzaeem@gmail.com> Stability   : Experimental Portability : Portable -Parses raw query to Haskell Algebraic Data Types+This module is responsible for parsing the JSONPath query -} module Data.Aeson.JSONPath.Parser   ( pQuery )   where -import qualified Data.Text                      as T import qualified Text.ParserCombinators.Parsec  as P -import Data.Functor                  (($>))-import Data.Char                     (ord, chr)-import Data.Maybe                    (isNothing, fromMaybe)-import Data.Scientific               (Scientific, scientific)-import GHC.Num                       (integerFromInt, integerToInt)-import Text.ParserCombinators.Parsec ((<|>))--import Data.Aeson.JSONPath.Query.Types+import Data.Aeson.JSONPath.Parser.Query (pRootQuery)+import Data.Aeson.JSONPath.Types  import Prelude  -- | Query parser pQuery :: P.Parser Query-pQuery = P.try pRootQuery <* P.eof--pRootQuery :: P.Parser Query-pRootQuery = do-  P.char '$'-  segs <- P.many (pSpaces *> pQuerySegment)-  return $ Query { queryType = Root, querySegments = segs }--pCurrentQuery :: P.Parser Query-pCurrentQuery = do-  P.char '@'-  segs <- P.many pQuerySegment-  return $ Query { queryType = Current, querySegments = segs }---pQuerySegment :: P.Parser QuerySegment-pQuerySegment = do-  dotdot <- P.optionMaybe (P.try $ P.string "..")-  seg <- pSegment $ isNothing dotdot-  let segType = if isNothing dotdot then Child else Descendant-  return $ QuerySegment { segmentType = segType, segment = seg }--pSegment :: Bool -> P.Parser Segment-pSegment isChild = P.try pBracketed-                <|> P.try (pDotted isChild)-                <|> P.try (pWildcardSeg isChild)---pBracketed :: P.Parser Segment-pBracketed = do-  P.char '['-  pSpaces-  sel <- pSelector-  optionalSels <- P.many pCommaSepSelectors-  pSpaces-  P.char ']'-  return $ Bracketed (sel:optionalSels)-    where-      pCommaSepSelectors :: P.Parser Selector-      pCommaSepSelectors = P.try $ pSpaces *> P.char ',' *> pSpaces *> pSelector---pDotted :: Bool -> P.Parser Segment-pDotted isChild = do-  (if isChild then P.string "." else P.string "")-  P.lookAhead (P.letter <|> P.oneOf "_" <|> pUnicodeChar)-  key <- T.pack <$> P.many1 (P.alphaNum <|> P.oneOf "_" <|> pUnicodeChar)-  return $ Dotted key---pWildcardSeg :: Bool -> P.Parser Segment-pWildcardSeg isChild = (if isChild then P.string "." else P.string "") *> P.char '*' $> WildcardSegment-  -pSelector :: P.Parser Selector-pSelector = P.try pName-         <|> P.try pSlice -         <|> P.try pIndex-         <|> P.try pWildcardSel-         <|> P.try pFilter--pName :: P.Parser Selector-pName = Name . T.pack <$> (P.try pSingleQuotted <|> P.try pDoubleQuotted)--pIndex :: P.Parser Selector-pIndex = Index <$> pSignedInt--pSlice :: P.Parser Selector-pSlice = do-  start <- P.optionMaybe (pSignedInt <* pSpaces)-  P.char ':'-  pSpaces-  end <- P.optionMaybe (pSignedInt <* pSpaces)-  step <- P.optionMaybe (P.char ':' *> P.optionMaybe (pSpaces *> pSignedInt))-  return $ ArraySlice (start, end, case step of-    Just (Just n) -> n-    _ -> 1)---pWildcardSel :: P.Parser Selector-pWildcardSel = P.char '*' $> WildcardSelector---pFilter :: P.Parser Selector-pFilter = do-  P.char '?'-  pSpaces-  Filter <$> pLogicalOrExpr---pLogicalOrExpr :: P.Parser LogicalOrExpr-pLogicalOrExpr = do-  expr <- pLogicalAndExpr-  optionalExprs <- P.many pOrSepLogicalAndExprs-  return $ LogicalOr (expr:optionalExprs)-    where-      pOrSepLogicalAndExprs :: P.Parser LogicalAndExpr-      pOrSepLogicalAndExprs = P.try $ pSpaces *> P.string "||" *> pSpaces *> pLogicalAndExpr--pLogicalAndExpr :: P.Parser LogicalAndExpr-pLogicalAndExpr = do-  expr <- pBasicExpr-  optionalExprs <- P.many pAndSepBasicExprs-  return $ LogicalAnd (expr:optionalExprs)-    where-      pAndSepBasicExprs :: P.Parser BasicExpr-      pAndSepBasicExprs = P.try $ pSpaces *> P.string "&&" *> pSpaces *> pBasicExpr--pBasicExpr :: P.Parser BasicExpr-pBasicExpr = P.try pParenExpr-          <|> P.try pComparisonExpr-          <|> P.try pTestExpr--pParenExpr :: P.Parser BasicExpr-pParenExpr = do-  notOp <- P.optionMaybe (P.char '!' <* pSpaces)-  P.char '('-  pSpaces-  expr <- pLogicalOrExpr-  pSpaces-  P.char ')'-  let parenExp = if isNothing notOp then Paren expr else NotParen expr-  return parenExp--pTestExpr :: P.Parser BasicExpr-pTestExpr = do-  notOp <- P.optionMaybe (P.char '!' <* pSpaces)-  q <- P.try pRootQuery <|> P.try pCurrentQuery-  let testExp = if isNothing notOp then Test q else NotTest q-  return testExp--pComparisonExpr :: P.Parser BasicExpr-pComparisonExpr = do-  leftC <- pComparable-  pSpaces-  compOp <- pComparisonOp-  pSpaces-  Comparison . Comp leftC compOp <$> pComparable--pComparisonOp :: P.Parser ComparisonOp-pComparisonOp = P.try (P.string ">=" $> GreaterOrEqual)-                <|> P.try (P.string "<=" $> LessOrEqual)-                <|> P.try (P.char '>' $> Greater)-                <|> P.try (P.char '<' $> Less)-                <|> P.try (P.string "!=" $> NotEqual)-                <|> P.try (P.string "==" $> Equal)--pComparable :: P.Parser Comparable-pComparable = P.try pCompLitString-              <|> P.try pCompLitNum-              <|> P.try pCompLitBool-              <|> P.try pCompLitNull-              <|> P.try pCompSQ--pCompLitString :: P.Parser Comparable-pCompLitString = CompLitString . T.pack <$> (P.try pSingleQuotted <|> P.try pDoubleQuotted)--pCompLitNum :: P.Parser Comparable-pCompLitNum = CompLitNum -           <$> (P.try (P.string "-0" $> (0 :: Scientific)) -- edge case-           <|> P.try pDoubleScientific -           <|> P.try pScientific)--pCompLitBool :: P.Parser Comparable-pCompLitBool = CompLitBool <$> (P.try (P.string "true" $> True) <|> P.try (P.string "false" $> False))--pCompLitNull :: P.Parser Comparable-pCompLitNull = P.string "null" $> CompLitNull--pCompSQ :: P.Parser Comparable-pCompSQ = CompSQ <$> (P.try pCurrentSingleQ <|> P.try pRootSingleQ)--pCurrentSingleQ :: P.Parser SingularQuery-pCurrentSingleQ = do-  P.char '@'-  segs <- P.many pSingularQuerySegment-  return $ SingularQuery { singularQueryType = CurrentSQ, singularQuerySegments = segs }--pRootSingleQ :: P.Parser SingularQuery-pRootSingleQ = do-  P.char '$'-  segs <- P.many pSingularQuerySegment-  return $ SingularQuery { singularQueryType = RootSQ, singularQuerySegments = segs }--pSingularQuerySegment :: P.Parser SingularQuerySegment-pSingularQuerySegment = P.try pSingularQNameSeg <|> P.try pSingularQIndexSeg--pSingularQNameSeg :: P.Parser SingularQuerySegment-pSingularQNameSeg = P.try pSingularQNameBracketed <|> P.try pSingularQNameDotted-  where-    pSingularQNameBracketed = do-      P.char '['-      name <- T.pack <$> (P.try pSingleQuotted <|> P.try pDoubleQuotted)-      P.char ']'-      return $ NameSQSeg name--    pSingularQNameDotted = do-      P.char '.'-      P.lookAhead (P.letter <|> P.oneOf "_" <|> pUnicodeChar)-      name <- T.pack <$> P.many1 (P.alphaNum <|> P.oneOf "_" <|> pUnicodeChar)-      return $ NameSQSeg name--pSingularQIndexSeg :: P.Parser SingularQuerySegment-pSingularQIndexSeg = do-  P.char '['-  idx <- pSignedInt-  P.char ']'-  return $ IndexSQSeg idx--pSignedInt :: P.Parser Int-pSignedInt = do-  P.notFollowedBy (P.string "-0" *> P.optional P.digit) -- no leading -011... etc-  P.notFollowedBy (P.char   '0' *> P.digit) -- no leading 011... etc-  sign <- P.optionMaybe $ P.char '-'-  num <- (read <$> P.many1 P.digit) :: P.Parser Integer-  checkNumOutOfRange num sign-  where-    minInt = -9007199254740991-    maxInt = 9007199254740991-    checkNumOutOfRange num (Just _) =-      if -num < minInt then fail "out of range"-      else return $ integerToInt (-num)--    checkNumOutOfRange num Nothing =-      if num > maxInt then fail "out of range"-      else return $ integerToInt num---- TODO: Fix Double parse error  "1.12e+23"-pScientific :: P.Parser Scientific-pScientific = do-  mantissa <- pSignedInt-  expo <- P.optionMaybe (P.oneOf "eE" *> pExponent)-  return $ scientific (integerFromInt mantissa) (fromMaybe 0 expo)--pDoubleScientific :: P.Parser Scientific-pDoubleScientific = do-  whole <- P.many1 P.digit-  P.char '.'-  frac <- P.many1 P.digit-  expo <- P.optionMaybe (P.oneOf "eE" *> pExponent)-  let num = read (whole ++ "." ++ frac ++ maybe "" (\x -> "e" ++ show x) expo) :: Scientific-  return num--pExponent :: P.Parser Int-pExponent = do-  sign <- P.optionMaybe (P.oneOf "+-")-  num <- read <$> P.many1 P.digit-  return $ case sign of-    Just '-' -> -num-    _        -> num--pUnicodeChar :: P.Parser Char-pUnicodeChar = P.satisfy inRange-  where-    inRange c = let code = ord c in-      (code >= 0x80 && code <= 0xD7FF) ||-      (code >= 0xE000 && code <= 0x10FFFF)---- https://www.rfc-editor.org/rfc/rfc9535#name-syntax-pSpaces :: P.Parser [Char]-pSpaces = P.many (P.oneOf " \n\r\t")--pSingleQuotted :: P.Parser String-pSingleQuotted = P.char '\'' *> P.many inQuote <* P.char '\''-  where-    inQuote = P.try pUnescaped-           <|> P.try (P.char '\"')-           <|> P.try (P.string "\\\'" $> '\'')-           <|> P.try pEscaped--pDoubleQuotted :: P.Parser String-pDoubleQuotted = P.char '\"' *> P.many inQuote <* P.char '\"'-  where-    inQuote = P.try pUnescaped-           <|> P.try (P.char '\'')-           <|> P.try (P.string "\\\"" $> '\"')-           <|> P.try pEscaped--pUnescaped :: P.Parser Char-pUnescaped = P.satisfy inRange-  where-    inRange c = let code = ord c in-      (code >= 0x20 && code <= 0x21) ||-      (code >= 0x23 && code <= 0x26) ||-      (code >= 0x28 && code <= 0x5B) ||-      (code >= 0x5D && code <= 0xD7FF) ||-      (code >= 0xE000 && code <= 0x10FFFF)--pEscaped :: P.Parser Char-pEscaped = do-  P.char '\\'-  P.try pEscapees <|> P.try pHexUnicode-  where-    pEscapees = P.try (P.char 'b' $> '\b')-            <|> P.try (P.char 'f' $> '\f')-            <|> P.try (P.char 'n' $> '\n')-            <|> P.try (P.char 'r' $> '\r')-            <|> P.try (P.char 't' $> '\t')-            <|> P.try (P.char '/')-            <|> P.try (P.char '\\')--pHexUnicode :: P.Parser Char-pHexUnicode = P.try pNonSurrogate <|> P.try pSurrogatePair-  where-    pNonSurrogate = P.try pNonSurrogateFirst <|> P.try pNonSurrogateSecond-      where-        pNonSurrogateFirst = do-          P.char 'u'-          c1 <- P.digit <|> P.oneOf "AaBbCcEeFf"-          c2 <- P.hexDigit-          c3 <- P.hexDigit-          c4 <- P.hexDigit-          return $ chr (read ("0x" ++ [c1,c2,c3,c4]) :: Int)--        pNonSurrogateSecond = do-          P.char 'u'-          c1 <- P.oneOf "Dd"-          c2 <- P.oneOf "01234567"-          c3 <- P.hexDigit-          c4 <- P.hexDigit-          return $ chr (read ("0x" ++ [c1,c2,c3,c4]) :: Int)--    pSurrogatePair = do-      P.char 'u'-      high <- pHighSurrogate-      P.char '\\'-      P.char 'u'-      fromHighAndLow high <$> pLowSurrogate-      where-        pHighSurrogate = do-          c1 <- P.oneOf "Dd"-          c2 <- P.oneOf "89AaBb"-          c3 <- P.hexDigit-          c4 <- P.hexDigit-          return (read ("0x" ++ [c1,c2,c3,c4]) :: Int)--        pLowSurrogate = do-          c1 <- P.oneOf "Dd"-          c2 <- P.oneOf "CcDdEeFf"-          c3 <- P.hexDigit-          c4 <- P.hexDigit-          return (read ("0x" ++ [c1,c2,c3,c4]) :: Int)-          -        fromHighAndLow hi lo = chr $ ((hi - 0xD800) * 0x400) + (lo - 0xDC00) + 0x10000+pQuery = pRootQuery <* P.eof
+ src/Data/Aeson/JSONPath/Parser/Common.hs view
@@ -0,0 +1,21 @@+module Data.Aeson.JSONPath.Parser.Common+  ( pSpaces+  , pUnicodeChar+  )+  where++import qualified Text.ParserCombinators.Parsec as P+import           Data.Char (ord)++import Prelude++-- https://www.rfc-editor.org/rfc/rfc9535#name-syntax+pSpaces :: P.Parser [Char]+pSpaces = P.many (P.oneOf " \n\r\t")++pUnicodeChar :: P.Parser Char+pUnicodeChar = P.satisfy inRange+  where+    inRange c = let code = ord c in+      (code >= 0x80 && code <= 0xD7FF) ||+      (code >= 0xE000 && code <= 0x10FFFF)
+ src/Data/Aeson/JSONPath/Parser/Filter.hs view
@@ -0,0 +1,150 @@+{-# OPTIONS_GHC -Wno-unused-do-bind #-}+module Data.Aeson.JSONPath.Parser.Filter+  ( pFilter )+  where++import qualified Data.Text                      as T+import qualified Text.ParserCombinators.Parsec  as P++import Data.Functor                  (($>))+import Data.Maybe                    (isNothing)+import Data.Scientific               (Scientific)+import Text.ParserCombinators.Parsec ((<|>))++import Data.Aeson.JSONPath.Parser.Name+import Data.Aeson.JSONPath.Parser.Number+import Data.Aeson.JSONPath.Parser.Common++import Data.Aeson.JSONPath.Types++import Prelude++pFilter :: P.Parser a -> P.Parser (Selector a)+pFilter pQ = do+  P.char '?'+  pSpaces+  Filter <$> pLogicalOrExpr pQ+++pLogicalOrExpr :: P.Parser a -> P.Parser (LogicalOrExpr a)+pLogicalOrExpr pQ = do+  expr <- pLogicalAndExpr pQ+  optionalExprs <- P.many $ pOrSepLogicalAndExprs pQ+  return $ LogicalOr (expr:optionalExprs)+    where+      pOrSepLogicalAndExprs :: P.Parser a -> P.Parser (LogicalAndExpr a)+      pOrSepLogicalAndExprs pQ' = P.try $ pSpaces *> P.string "||" *> pSpaces *> pLogicalAndExpr pQ'++pLogicalAndExpr :: P.Parser a -> P.Parser (LogicalAndExpr a)+pLogicalAndExpr pQ = do+  expr <- pBasicExpr pQ+  optionalExprs <- P.many $ pAndSepBasicExprs pQ+  return $ LogicalAnd (expr:optionalExprs)+    where+      pAndSepBasicExprs :: P.Parser a -> P.Parser (BasicExpr a)+      pAndSepBasicExprs pQ' = P.try $ pSpaces *> P.string "&&" *> pSpaces *> pBasicExpr pQ'++pBasicExpr :: P.Parser a -> P.Parser (BasicExpr a)+pBasicExpr pQ +  = P.try (pParenExpr pQ)+ <|> P.try pComparisonExpr+ <|> P.try (pTestExpr pQ)++pParenExpr :: P.Parser a -> P.Parser (BasicExpr a)+pParenExpr pQ = do+  notOp <- P.optionMaybe (P.char '!' <* pSpaces)+  P.char '('+  pSpaces+  expr <- pLogicalOrExpr pQ+  pSpaces+  P.char ')'+  let parenExp = if isNothing notOp then Paren expr else NotParen expr+  return parenExp++pTestExpr :: P.Parser a -> P.Parser (BasicExpr a)+pTestExpr pQ = do+  notOp <- P.optionMaybe (P.char '!' <* pSpaces)+  q <- P.try (FilterQuery <$> pQ)+  let testExp = if isNothing notOp then Test q else NotTest q+  return testExp++pComparisonExpr :: P.Parser (BasicExpr a)+pComparisonExpr = do+  leftC <- pComparable+  pSpaces+  compOp <- pComparisonOp+  pSpaces+  Comparison . Comp leftC compOp <$> pComparable++pComparisonOp :: P.Parser ComparisonOp+pComparisonOp = P.try (P.string ">=" $> GreaterOrEqual)+             <|> P.try (P.string "<=" $> LessOrEqual)+             <|> P.try (P.char '>' $> Greater)+             <|> P.try (P.char '<' $> Less)+             <|> P.try (P.string "!=" $> NotEqual)+             <|> P.try (P.string "==" $> Equal)++pComparable :: P.Parser Comparable+pComparable = P.try pCompLit <|> P.try pCompSQ++pCompLit :: P.Parser Comparable+pCompLit = CompLit+            <$> (P.try pLitString+            <|> P.try pLitNum+            <|> P.try pLitBool+            <|> P.try pLitNull)++pLitString :: P.Parser Literal+pLitString = LitString . T.pack <$> (P.try pSingleQuotted <|> P.try pDoubleQuotted)++pLitNum :: P.Parser Literal+pLitNum = LitNum +           <$> (P.try (P.string "-0" $> (0 :: Scientific)) -- edge case+           <|> P.try pDoubleScientific +           <|> P.try pScientific)++pLitBool :: P.Parser Literal+pLitBool = LitBool <$> (P.try (P.string "true" $> True) <|> P.try (P.string "false" $> False))++pLitNull :: P.Parser Literal+pLitNull = P.string "null" $> LitNull++pCompSQ :: P.Parser Comparable+pCompSQ = CompSQ <$> (P.try pCurrentSingleQ <|> P.try pRootSingleQ)++pCurrentSingleQ :: P.Parser SingularQuery+pCurrentSingleQ = do+  P.char '@'+  segs <- P.many $ P.try (pSpaces *> pSingularQuerySegment)+  return $ SingularQuery { singularQueryType = CurrentSQ, singularQuerySegments = segs }++pRootSingleQ :: P.Parser SingularQuery+pRootSingleQ = do+  P.char '$'+  segs <- P.many $ P.try (pSpaces *> pSingularQuerySegment)+  return $ SingularQuery { singularQueryType = RootSQ, singularQuerySegments = segs }++pSingularQuerySegment :: P.Parser SingularQuerySegment+pSingularQuerySegment = P.try pSingularQNameSeg <|> P.try pSingularQIndexSeg++pSingularQNameSeg :: P.Parser SingularQuerySegment+pSingularQNameSeg = P.try pSingularQNameBracketed <|> P.try pSingularQNameDotted+  where+    pSingularQNameBracketed = do+      P.char '['+      name <- T.pack <$> (P.try pSingleQuotted <|> P.try pDoubleQuotted)+      P.char ']'+      return $ NameSQSeg name++    pSingularQNameDotted = do+      P.char '.'+      P.lookAhead (P.letter <|> P.oneOf "_" <|> pUnicodeChar)+      name <- T.pack <$> P.many1 (P.alphaNum <|> P.oneOf "_" <|> pUnicodeChar)+      return $ NameSQSeg name++pSingularQIndexSeg :: P.Parser SingularQuerySegment+pSingularQIndexSeg = do+  P.char '['+  idx <- pSignedInt+  P.char ']'+  return $ IndexSQSeg idx
+ src/Data/Aeson/JSONPath/Parser/Name.hs view
@@ -0,0 +1,97 @@+{-# OPTIONS_GHC -Wno-unused-do-bind #-}+module Data.Aeson.JSONPath.Parser.Name+  ( pSingleQuotted+  , pDoubleQuotted+  )+  where++import qualified Text.ParserCombinators.Parsec  as P++import Data.Functor                  (($>))+import Data.Char                     (ord, chr)+import Text.ParserCombinators.Parsec ((<|>))++import Prelude++pSingleQuotted :: P.Parser String+pSingleQuotted = P.char '\'' *> P.many inQuote <* P.char '\''+  where+    inQuote = P.try pUnescaped+           <|> P.try (P.char '\"')+           <|> P.try (P.string "\\\'" $> '\'')+           <|> P.try pEscaped++pDoubleQuotted :: P.Parser String+pDoubleQuotted = P.char '\"' *> P.many inQuote <* P.char '\"'+  where+    inQuote = P.try pUnescaped+           <|> P.try (P.char '\'')+           <|> P.try (P.string "\\\"" $> '\"')+           <|> P.try pEscaped++pUnescaped :: P.Parser Char+pUnescaped = P.satisfy inRange+  where+    inRange c = let code = ord c in+      (code >= 0x20 && code <= 0x21) ||+      (code >= 0x23 && code <= 0x26) ||+      (code >= 0x28 && code <= 0x5B) ||+      (code >= 0x5D && code <= 0xD7FF) ||+      (code >= 0xE000 && code <= 0x10FFFF)++pEscaped :: P.Parser Char+pEscaped = do+  P.char '\\'+  P.try pEscapees <|> P.try pHexUnicode+  where+    pEscapees = P.try (P.char 'b' $> '\b')+            <|> P.try (P.char 'f' $> '\f')+            <|> P.try (P.char 'n' $> '\n')+            <|> P.try (P.char 'r' $> '\r')+            <|> P.try (P.char 't' $> '\t')+            <|> P.try (P.char '/')+            <|> P.try (P.char '\\')++pHexUnicode :: P.Parser Char+pHexUnicode = P.try pNonSurrogate <|> P.try pSurrogatePair+  where+    pNonSurrogate = P.try pNonSurrogateFirst <|> P.try pNonSurrogateSecond+      where+        pNonSurrogateFirst = do+          P.char 'u'+          c1 <- P.digit <|> P.oneOf "AaBbCcEeFf"+          c2 <- P.hexDigit+          c3 <- P.hexDigit+          c4 <- P.hexDigit+          return $ chr (read ("0x" ++ [c1,c2,c3,c4]) :: Int)++        pNonSurrogateSecond = do+          P.char 'u'+          c1 <- P.oneOf "Dd"+          c2 <- P.oneOf "01234567"+          c3 <- P.hexDigit+          c4 <- P.hexDigit+          return $ chr (read ("0x" ++ [c1,c2,c3,c4]) :: Int)++    pSurrogatePair = do+      P.char 'u'+      high <- pHighSurrogate+      P.char '\\'+      P.char 'u'+      fromHighAndLow high <$> pLowSurrogate+      where+        pHighSurrogate = do+          c1 <- P.oneOf "Dd"+          c2 <- P.oneOf "89AaBb"+          c3 <- P.hexDigit+          c4 <- P.hexDigit+          return (read ("0x" ++ [c1,c2,c3,c4]) :: Int)++        pLowSurrogate = do+          c1 <- P.oneOf "Dd"+          c2 <- P.oneOf "CcDdEeFf"+          c3 <- P.hexDigit+          c4 <- P.hexDigit+          return (read ("0x" ++ [c1,c2,c3,c4]) :: Int)++        fromHighAndLow hi lo = chr $ ((hi - 0xD800) * 0x400) + (lo - 0xDC00) + 0x10000
+ src/Data/Aeson/JSONPath/Parser/Number.hs view
@@ -0,0 +1,57 @@+{-# OPTIONS_GHC -Wno-unused-do-bind #-}+module Data.Aeson.JSONPath.Parser.Number+  ( pSignedInt+  , pScientific+  , pDoubleScientific+  )+  where++import qualified Text.ParserCombinators.Parsec  as P++import Data.Maybe                    (fromMaybe)+import Data.Scientific               (Scientific, scientific)+import GHC.Num                       (integerFromInt, integerToInt)++import Prelude++pSignedInt :: P.Parser Int+pSignedInt = do+  P.notFollowedBy (P.string "-0" *> P.optional P.digit) -- no leading -011... etc+  P.notFollowedBy (P.char   '0' *> P.digit) -- no leading 011... etc+  sign <- P.optionMaybe $ P.char '-'+  num <- (read <$> P.many1 P.digit) :: P.Parser Integer+  checkNumOutOfRange num sign+  where+    minInt = -9007199254740991+    maxInt = 9007199254740991+    checkNumOutOfRange num (Just _) =+      if -num < minInt then fail "out of range"+      else return $ integerToInt (-num)++    checkNumOutOfRange num Nothing =+      if num > maxInt then fail "out of range"+      else return $ integerToInt num++-- TODO: Fix Double parse error  "1.12e+23"+pScientific :: P.Parser Scientific+pScientific = do+  mantissa <- pSignedInt+  expo <- P.optionMaybe (P.oneOf "eE" *> pExponent)+  return $ scientific (integerFromInt mantissa) (fromMaybe 0 expo)++pDoubleScientific :: P.Parser Scientific+pDoubleScientific = do+  whole <- P.many1 P.digit+  P.char '.'+  frac <- P.many1 P.digit+  expo <- P.optionMaybe (P.oneOf "eE" *> pExponent)+  let num = read (whole ++ "." ++ frac ++ maybe "" (\x -> "e" ++ show x) expo) :: Scientific+  return num++pExponent :: P.Parser Int+pExponent = do+  sign <- P.optionMaybe (P.oneOf "+-")+  num <- read <$> P.many1 P.digit+  return $ case sign of+    Just '-' -> -num+    _        -> num
+ src/Data/Aeson/JSONPath/Parser/Query.hs view
@@ -0,0 +1,105 @@+{-# OPTIONS_GHC -Wno-unused-do-bind #-}+module Data.Aeson.JSONPath.Parser.Query+  ( pRootQuery+  , pCurrentQuery )+  where++import qualified Data.Text                      as T+import qualified Text.ParserCombinators.Parsec  as P++import Data.Functor                  (($>))+import Data.Maybe                    (isNothing)+import Text.ParserCombinators.Parsec ((<|>))++import Data.Aeson.JSONPath.Parser.Filter (pFilter)+import Data.Aeson.JSONPath.Parser.Name+import Data.Aeson.JSONPath.Parser.Number+import Data.Aeson.JSONPath.Parser.Common+import Data.Aeson.JSONPath.Types++import Prelude++pRootQuery :: P.Parser Query+pRootQuery = do+  P.char '$'+  segs <- P.many $ P.try pSpacedOutSegments+  return $ Query { queryType = Root, querySegments = segs }+    where+      pQ = P.try pRootQuery <|> P.try pCurrentQuery+      pSpacedOutSegments = pSpaces *> pQuerySegment pQ++pCurrentQuery :: P.Parser Query+pCurrentQuery = do+  P.char '@'+  segs <- P.many $ P.try pSpacedOutSegments+  return $ Query { queryType = Current, querySegments = segs }+    where+      pQ = P.try pRootQuery <|> P.try pCurrentQuery+      pSpacedOutSegments = pSpaces *> pQuerySegment pQ+++pQuerySegment :: P.Parser a -> P.Parser (QuerySegment a)+pQuerySegment pQ = do+  dotdot <- P.optionMaybe (P.try $ P.string "..")+  seg <- pSegment pQ $ isNothing dotdot+  let segType = if isNothing dotdot then Child else Descendant+  return $ QuerySegment { segmentType = segType, segment = seg }++pSegment :: P.Parser a -> Bool -> P.Parser (Segment a)+pSegment pQ isChild+        = P.try (pBracketed pQ)+       <|> P.try (pDotted isChild)+       <|> P.try (pWildcardSeg isChild)++pBracketed :: P.Parser a -> P.Parser (Segment a)+pBracketed pQ = do+  P.char '['+  pSpaces+  sel <- pSelector pQ+  optionalSels <- P.many $ pCommaSepSelectors pQ+  pSpaces+  P.char ']'+  return $ Bracketed (sel:optionalSels)+    where+      pCommaSepSelectors :: P.Parser a -> P.Parser (Selector a)+      pCommaSepSelectors p = P.try $ pSpaces *> P.char ',' *> pSpaces *> pSelector p+++pDotted :: Bool -> P.Parser (Segment a)+pDotted isChild = do+  (if isChild then P.string "." else P.string "")+  P.lookAhead (P.letter <|> P.oneOf "_" <|> pUnicodeChar)+  key <- T.pack <$> P.many1 (P.alphaNum <|> P.oneOf "_" <|> pUnicodeChar)+  return $ Dotted key+++pWildcardSeg :: Bool -> P.Parser (Segment a)+pWildcardSeg isChild = (if isChild then P.string "." else P.string "") *> P.char '*' $> WildcardSegment+  +pSelector :: P.Parser a -> P.Parser (Selector a)+pSelector pQ = P.try pName+                   <|> P.try pSlice +                   <|> P.try pIndex+                   <|> P.try pWildcardSel+                   <|> P.try (pFilter pQ)++pName :: P.Parser (Selector a)+pName = Name . T.pack <$> (P.try pSingleQuotted <|> P.try pDoubleQuotted)++pIndex :: P.Parser (Selector a)+pIndex = Index <$> pSignedInt++pSlice :: P.Parser (Selector a)+pSlice = do+  start <- P.optionMaybe (pSignedInt <* pSpaces)+  P.char ':'+  pSpaces+  end <- P.optionMaybe (pSignedInt <* pSpaces)+  step <- P.optionMaybe (P.char ':' *> P.optionMaybe (pSpaces *> pSignedInt))+  return $ ArraySlice (start, end, case step of+    Just (Just n) -> n+    _ -> 1)+++pWildcardSel :: P.Parser (Selector a)+pWildcardSel = P.char '*' $> WildcardSelector
src/Data/Aeson/JSONPath/Query.hs view
@@ -1,290 +1,18 @@-{-# LANGUAGE RecordWildCards #-} {- | Module      : Data.Aeson.JSONPath.Query-Description : Algorithm for query runner+Description : Execute JSONPath Query after parsing Copyright   : (c) 2024-2025 Taimoor Zaeem License     : MIT Maintainer  : Taimoor Zaeem <mtaimoorzaeem@gmail.com> Stability   : Experimental Portability : Portable -This module contains core functions that runs the query on 'Value'.+This module is responsible for executing the JSONPath query -} module Data.Aeson.JSONPath.Query-  ( Queryable (..) )+  (+    module Data.Aeson.JSONPath.Query.Query+  )   where -import Control.Monad                   (join)-import Data.Aeson                      (Value)-import Data.Vector                     (Vector)--import qualified Data.Aeson            as JSON-import qualified Data.Aeson.KeyMap     as KM-import qualified Data.Aeson.Key        as K-import qualified Data.Text             as T-import qualified Data.Vector           as V--import Data.Aeson.JSONPath.Query.Types--import Prelude---- |-class Queryable a where-  query'        :: a -> Value -> Value -> Vector Value-  queryLocated' :: a -> Value -> Value -> String -> Vector (String,Value)--instance Queryable Query where-  query'        = qQuery-  queryLocated' = qQueryLocated--instance Queryable QuerySegment where-  query'        = qQuerySegment-  queryLocated' = qQuerySegmentLocated--instance Queryable Segment where-  query'        = qSegment-  queryLocated' = qSegmentLocated--instance Queryable Selector where-  query'        = qSelector-  queryLocated' = qSelectorLocated---- TODO: the whole module is kinda bloated, refactor---    Blockers with refactoring: qQuery is used recursively--qQuery :: Query -> Value -> Value -> Vector Value-qQuery Query{..} root current = case queryType of-  Root    -> foldl applySegment (V.singleton root)    querySegments-  Current -> foldl applySegment (V.singleton current) querySegments-  where-    applySegment :: Vector Value -> QuerySegment -> Vector Value-    applySegment vec seg = join $ V.map (qQuerySegment seg root) vec--qQueryLocated :: Query -> Value -> Value -> String -> Vector (String,Value)-qQueryLocated Query{..} root current loc = case queryType of-  Root    -> foldl applySegment (V.singleton (loc,root))    querySegments-  Current -> foldl applySegment (V.singleton (loc,current)) querySegments-  where-    applySegment :: Vector (String,Value) -> QuerySegment -> Vector (String,Value)-    applySegment vec seg = join $ V.map (\(location,cur) -> qQuerySegmentLocated seg root cur location) vec--qQuerySegment :: QuerySegment -> Value -> Value -> Vector Value-qQuerySegment QuerySegment{..} root current = case segmentType of-  Child      -> joinAfterMap $ V.singleton current-  Descendant -> joinAfterMap $ allElemsRecursive current-  where-    joinAfterMap x = join $ V.map (qSegment segment root) x--qQuerySegmentLocated :: QuerySegment -> Value -> Value -> String -> Vector (String, Value)-qQuerySegmentLocated QuerySegment{..} root current loc = case segmentType of-  Child      -> joinAfterMap $ V.singleton (loc,current)-  Descendant -> joinAfterMap $ allElemsRecursiveLocated (loc,current)-  where-    joinAfterMap x = join $ V.map (\(location,cur) -> qSegmentLocated segment root cur location) x--qSegment :: Segment -> Value -> Value -> Vector Value-qSegment (Bracketed sels) root current = V.concat $ map (\sel -> qSelector sel root current) sels-qSegment (Dotted key) root current = qSelector (Name key) root current-qSegment WildcardSegment root current = qSelector WildcardSelector root current--qSegmentLocated :: Segment -> Value -> Value -> String -> Vector (String,Value)-qSegmentLocated (Bracketed sels) root current loc = V.concat $ map (\sel -> qSelectorLocated sel root current loc) sels-qSegmentLocated (Dotted key) root current loc = qSelectorLocated (Name key) root current loc-qSegmentLocated WildcardSegment root current loc = qSelectorLocated WildcardSelector root current loc----- TODO: Looks kinda ugly, make it pretty <3-allElemsRecursive :: Value -> Vector Value-allElemsRecursive o@(JSON.Object obj) = V.concat [-    V.singleton o,-    V.concat $ map allElemsRecursive (KM.elems obj)-  ]-allElemsRecursive a@(JSON.Array arr) = V.concat [-    V.singleton a,-    V.concat $ map allElemsRecursive (V.toList arr)-  ]-allElemsRecursive _ = V.empty---- TODO: Looks kinda ugly, make it pretty <3-allElemsRecursiveLocated :: (String,Value) -> Vector (String,Value)-allElemsRecursiveLocated (loc, o@(JSON.Object obj)) = V.concat [-    V.singleton (loc,o),-    V.concat $ zipWith (curry allElemsRecursiveLocated) (replicate (length (KM.elems obj)) loc) (KM.elems obj)-  ]-allElemsRecursiveLocated (loc, a@(JSON.Array arr)) = V.concat [-    V.singleton (loc,a),-    V.concat $ zipWith (curry allElemsRecursiveLocated) (replicate (V.length arr) loc) (V.toList arr)-  ]-allElemsRecursiveLocated _ = V.empty---qSelector :: Selector -> Value -> Value -> Vector Value-qSelector (Name key) _ (JSON.Object obj) = maybe V.empty  V.singleton $ KM.lookup (K.fromText key) obj-qSelector (Name _) _ _ = V.empty-qSelector (Index idx) _ (JSON.Array arr) = maybe V.empty V.singleton $ if idx >= 0 then (V.!?) arr idx else (V.!?) arr (idx + V.length arr)-qSelector (Index _) _ _ = V.empty-qSelector (ArraySlice startEndStep) _ (JSON.Array arr) = sliceArray startEndStep arr-qSelector (ArraySlice _) _ _ = V.empty-qSelector (Filter orExpr) root current = filterOrExpr orExpr root current-qSelector WildcardSelector _ cur = case cur of-    (JSON.Object obj) -> V.fromList $ KM.elems obj-    (JSON.Array arr)  -> arr-    _                 -> V.empty--qSelectorLocated :: Selector -> Value -> Value -> String -> Vector (String,Value)-qSelectorLocated (Name key) _ (JSON.Object obj) loc = maybe V.empty (\x-> V.singleton (loc ++ "['" ++ T.unpack key ++ "']", x)) $ KM.lookup (K.fromText key) obj-qSelectorLocated (Name _) _ _ _ = V.empty-qSelectorLocated (Index idx) _ (JSON.Array arr) loc = maybe V.empty (\x-> V.singleton (newLocation, x)) $ (V.!?) arr (getIndex idx)-  where-    newLocation = loc ++ "[" ++ show (getIndex idx) ++ "]"-    getIndex i = if i >= 0 then i else i + V.length arr-qSelectorLocated (Index _) _ _ _ = V.empty-qSelectorLocated (ArraySlice (start,end,step)) _ (JSON.Array arr) loc = sliceArrayLocated (start,end,step) $ V.zip (V.fromList locs) arr-  where-    locs = [ loc ++ "[" ++ show i ++ "]" | i <- indices ]-    indices = [0..(V.length arr - 1)]-qSelectorLocated (ArraySlice _) _ _ _ = V.empty-qSelectorLocated (Filter orExpr) root cur loc = filterOrExprLocated orExpr root cur loc-qSelectorLocated WildcardSelector _ cur loc = case cur of-    (JSON.Object obj) -> V.fromList $ zip (locsWithKeys obj) (KM.elems obj)-    (JSON.Array arr)  -> V.zip (V.fromList (locsWithIdxs arr)) arr-    _                 -> V.empty-    where-      locsWithKeys obj = map (\x -> loc ++ "['" ++ K.toString x ++ "']") (KM.keys obj)-      locsWithIdxs arr = map (\x -> loc ++ "[" ++ show x ++ "]") [0..(V.length arr)]---sliceArray :: (Maybe Int, Maybe Int, Int) -> Vector Value -> Vector Value-sliceArray (start,end,step) vec =-  case compare step 0 of-    GT -> getSliceForward (maybe 0 normalize start) (maybe len normalize end) step vec-    LT -> getSliceReverse (maybe (len-1) normalize start) (maybe (-1) normalize end) step vec-    EQ -> V.empty-    where-      -- TODO: Looks kinda ugly, make it pretty <3-      len = V.length vec-      normalize i = if i >= 0 then i else len + i--      getSliceForward st en stp arr = loop lower V.empty-        where-          (lower,upper) = (min (max st 0) len, min (max en 0) len)--          loop i acc =-            if i < upper-              then loop (i+stp) $ V.snoc acc $ (V.!) arr (normalize i)-            else-              acc--      getSliceReverse st en stp arr = loop upper V.empty-        where-          (lower,upper) = (min (max en (-1)) (len-1), min (max st (-1)) (len-1))--          loop i acc =-            if lower < i-              then loop (i+stp) $ V.snoc acc $ (V.!) arr (normalize i)-            else-              acc---sliceArrayLocated :: (Maybe Int, Maybe Int, Int) -> Vector (String,Value) -> Vector (String,Value)-sliceArrayLocated (start,end,step) vec =-  case compare step 0 of-    GT -> getSliceForward (maybe 0 normalize start) (maybe len normalize end) step vec-    LT -> getSliceReverse (maybe (len-1) normalize start) (maybe (-1) normalize end) step vec-    EQ -> V.empty-    where-      -- TODO: Looks kinda ugly, make it pretty <3-      len = V.length vec-      normalize i = if i >= 0 then i else len + i--      getSliceForward st en stp arr = loop lower V.empty-        where-          (lower,upper) = (min (max st 0) len, min (max en 0) len)--          loop i acc =-            if i < upper-              then loop (i+stp) $ V.snoc acc $ (V.!) arr (normalize i)-            else-              acc--      getSliceReverse st en stp arr = loop upper V.empty-        where-          (lower,upper) = (min (max en (-1)) (len-1), min (max st (-1)) (len-1))--          loop i acc =-            if lower < i-              then loop (i+stp) $ V.snoc acc $ (V.!) arr (normalize i)-            else-              acc--filterOrExpr :: LogicalOrExpr -> Value -> Value -> Vector Value-filterOrExpr expr root (JSON.Object obj) = V.filter (evaluateLogicalOrExpr expr root) (V.fromList $ KM.elems obj)-filterOrExpr expr root (JSON.Array arr) = V.filter (evaluateLogicalOrExpr expr root) arr-filterOrExpr _ _ _ = V.empty--filterOrExprLocated :: LogicalOrExpr -> Value -> Value -> String -> Vector (String,Value)-filterOrExprLocated expr root (JSON.Object obj) loc = V.filter (\(_,x) -> evaluateLogicalOrExpr expr root x) (V.fromList $ zip locsWithKeys (KM.elems obj))-  where-    locsWithKeys = map (\x -> loc ++ "['" ++ K.toString x ++ "']") (KM.keys obj)-filterOrExprLocated expr root (JSON.Array arr) loc = V.filter (\(_,x) -> evaluateLogicalOrExpr expr root x) (V.zip (V.fromList locsWithIdxs) arr)-  where-    locsWithIdxs = map (\x -> loc ++ "[" ++ show x ++ "]") [0..(V.length arr - 1)]-filterOrExprLocated _ _ _ _ = V.empty---evaluateLogicalOrExpr :: LogicalOrExpr -> Value -> Value -> Bool-evaluateLogicalOrExpr (LogicalOr exprs) root cur = any (\x -> evaluateLogicalAndExpr x root cur) exprs---evaluateLogicalAndExpr :: LogicalAndExpr -> Value -> Value -> Bool-evaluateLogicalAndExpr (LogicalAnd exprs) root cur = all (\x -> evaluateBasicExpr x root cur) exprs---evaluateBasicExpr :: BasicExpr -> Value -> Value -> Bool-evaluateBasicExpr (Paren expr) root cur = evaluateLogicalOrExpr expr root cur-evaluateBasicExpr (NotParen expr) root cur = not $ evaluateLogicalOrExpr expr root cur-evaluateBasicExpr (Test expr) root cur = evaluateTestExpr expr root cur-evaluateBasicExpr (NotTest expr) root cur = not $ evaluateTestExpr expr root cur-evaluateBasicExpr (Comparison expr) root cur = evaluateCompExpr expr root cur---evaluateTestExpr :: TestExpr -> Value -> Value -> Bool-evaluateTestExpr expr root cur = not $ null $ qQuery expr root cur---evaluateCompExpr :: ComparisonExpr -> Value -> Value -> Bool-evaluateCompExpr (Comp leftC op rightC) root cur  = compareVals op (getComparableVal leftC root cur) (getComparableVal rightC root cur)---compareVals :: ComparisonOp -> Maybe Value -> Maybe Value -> Bool-compareVals Less (Just (JSON.String s1)) (Just (JSON.String s2)) = s1 < s2-compareVals Less (Just (JSON.Number n1)) (Just (JSON.Number n2)) = n1 < n2-compareVals Less _  _ = False--compareVals LessOrEqual    o1 o2 = compareVals Less o1 o2 || compareVals Equal o1 o2-compareVals Greater        o1 o2 = compareVals Less o2 o1-compareVals GreaterOrEqual o1 o2 = compareVals Less o2 o1 || compareVals Equal o1 o2-compareVals Equal          o1 o2 = o1 == o2-compareVals NotEqual       o1 o2 = o1 /= o2---getComparableVal :: Comparable -> Value -> Value -> Maybe Value-getComparableVal (CompLitNum num) _ _ = Just $ JSON.Number num-getComparableVal (CompLitString txt) _ _ = Just $ JSON.String txt-getComparableVal (CompLitBool bool) _ _ = Just $ JSON.Bool bool-getComparableVal CompLitNull _ _ = Just JSON.Null-getComparableVal (CompSQ SingularQuery{..}) root cur = case singularQueryType of-  RootSQ -> traverseSingularQSegs (Just root) singularQuerySegments-  CurrentSQ -> traverseSingularQSegs (Just cur) singularQuerySegments---traverseSingularQSegs :: Maybe Value -> [SingularQuerySegment] -> Maybe Value-traverseSingularQSegs = foldl lookupSingleQSeg----- TODO: There is a bug here, not existing shouldn't give null--- See: https://www.rfc-editor.org/rfc/rfc9535#name-examples-6-lookupSingleQSeg :: Maybe Value -> SingularQuerySegment -> Maybe Value-lookupSingleQSeg (Just (JSON.Object obj)) (NameSQSeg txt) = KM.lookup (K.fromText txt) obj-lookupSingleQSeg (Just (JSON.Array arr)) (IndexSQSeg idx) = (V.!?) arr idx-lookupSingleQSeg _ _ = Nothing+import Data.Aeson.JSONPath.Query.Query
+ src/Data/Aeson/JSONPath/Query/Filter.hs view
@@ -0,0 +1,90 @@+{-# LANGUAGE RecordWildCards #-}+module Data.Aeson.JSONPath.Query.Filter+  ( filterOrExpr+  , filterOrExprLocated )+  where++import Data.Aeson                      (Value)+import Data.Vector                     (Vector)++import qualified Data.Aeson            as JSON+import qualified Data.Aeson.KeyMap     as KM+import qualified Data.Aeson.Key        as K+import qualified Data.Vector           as V++import Data.Aeson.JSONPath.Types++import Prelude++filterOrExpr :: LogicalOrExpr Query -> QueryState -> Vector Value+filterOrExpr expr qS@QueryState{ curVal=(JSON.Object obj) } = V.filter (\cur -> evaluateLogicalOrExpr expr qS{ curVal=cur}) (V.fromList $ KM.elems obj)+filterOrExpr expr qS@QueryState{ curVal=(JSON.Array arr) } = V.filter (\cur -> evaluateLogicalOrExpr expr qS{ curVal=cur }) arr+filterOrExpr _ _ = V.empty++filterOrExprLocated :: LogicalOrExpr Query -> QueryState -> String -> Vector (String,Value)+filterOrExprLocated expr  qS@QueryState{ curVal=(JSON.Object obj) } loc = V.filter (\(_,x) -> evaluateLogicalOrExpr expr qS{ curVal=x}) (V.fromList $ zip locsWithKeys (KM.elems obj))+  where+    locsWithKeys = map (\x -> loc ++ "['" ++ K.toString x ++ "']") (KM.keys obj)+filterOrExprLocated expr qS@QueryState{ curVal=(JSON.Array arr) } loc = V.filter (\(_,x) -> evaluateLogicalOrExpr expr qS{ curVal=x}) (V.zip (V.fromList locsWithIdxs) arr)+  where+    locsWithIdxs = map (\x -> loc ++ "[" ++ show x ++ "]") [0..(V.length arr - 1)]+filterOrExprLocated _ _ _ = V.empty+++evaluateLogicalOrExpr :: LogicalOrExpr Query -> QueryState -> Bool+evaluateLogicalOrExpr (LogicalOr exprs) qS = any (`evaluateLogicalAndExpr` qS) exprs+++evaluateLogicalAndExpr :: LogicalAndExpr Query -> QueryState -> Bool+evaluateLogicalAndExpr (LogicalAnd exprs) qS = all (`evaluateBasicExpr` qS) exprs+++evaluateBasicExpr :: BasicExpr Query -> QueryState -> Bool+evaluateBasicExpr (Paren expr)      qS = evaluateLogicalOrExpr expr qS+evaluateBasicExpr (NotParen expr)   qS = not $ evaluateLogicalOrExpr expr qS+evaluateBasicExpr (Test expr)       qS = evaluateTestExpr expr qS+evaluateBasicExpr (NotTest expr)    qS = not $ evaluateTestExpr expr qS+evaluateBasicExpr (Comparison expr) qS = evaluateCompExpr expr qS+++evaluateTestExpr :: TestExpr Query -> QueryState -> Bool+evaluateTestExpr (FilterQuery expr) qS@QueryState{..} = not $ null $ executeQuery expr qS+++evaluateCompExpr :: ComparisonExpr -> QueryState -> Bool+evaluateCompExpr (Comp leftC op rightC) qS  = compareVals op (getComparableVal leftC qS) (getComparableVal rightC qS)+++compareVals :: ComparisonOp -> Maybe Value -> Maybe Value -> Bool+compareVals Less (Just (JSON.String s1)) (Just (JSON.String s2)) = s1 < s2+compareVals Less (Just (JSON.Number n1)) (Just (JSON.Number n2)) = n1 < n2+compareVals Less _  _ = False++compareVals LessOrEqual    o1 o2 = compareVals Less o1 o2 || compareVals Equal o1 o2+compareVals Greater        o1 o2 = compareVals Less o2 o1+compareVals GreaterOrEqual o1 o2 = compareVals Less o2 o1 || compareVals Equal o1 o2+compareVals Equal          o1 o2 = o1 == o2+compareVals NotEqual       o1 o2 = o1 /= o2+++getComparableVal :: Comparable -> QueryState -> Maybe Value+getComparableVal (CompLit lit) _ = +  case lit of+    LitString txt -> Just $ JSON.String txt+    LitNum num    -> Just $ JSON.Number num+    LitBool bool  -> Just $ JSON.Bool bool+    LitNull       -> Just JSON.Null++getComparableVal (CompSQ SingularQuery{..}) QueryState{..} = case singularQueryType of+  RootSQ -> traverseSingularQSegs (Just rootVal) singularQuerySegments+  CurrentSQ -> traverseSingularQSegs (Just curVal) singularQuerySegments+++traverseSingularQSegs :: Maybe Value -> [SingularQuerySegment] -> Maybe Value+traverseSingularQSegs = foldl lookupSingleQSeg+++lookupSingleQSeg :: Maybe Value -> SingularQuerySegment -> Maybe Value+lookupSingleQSeg (Just (JSON.Object obj)) (NameSQSeg txt) = KM.lookup (K.fromText txt) obj+lookupSingleQSeg (Just (JSON.Array arr)) (IndexSQSeg idx) = (V.!?) arr idx+lookupSingleQSeg _ _ = Nothing
+ src/Data/Aeson/JSONPath/Query/Query.hs view
@@ -0,0 +1,35 @@+{-# LANGUAGE RecordWildCards #-}+module Data.Aeson.JSONPath.Query.Query+  ( qQuery+  , qQueryLocated+  )+  where++import Control.Monad                   (join)+import Data.Aeson                      (Value)+import Data.Vector                     (Vector)++import qualified Data.Vector           as V++import Data.Aeson.JSONPath.Types+import Data.Aeson.JSONPath.Query.Segment++import Prelude++-- | Runs the JSONPath Query+qQuery :: Query -> QueryState -> Vector Value+qQuery Query{..} qS@QueryState{..} = case queryType of+  Root    -> foldl applySegment (V.singleton rootVal) querySegments+  Current -> foldl applySegment (V.singleton curVal) querySegments+  where+    applySegment :: Vector Value -> QuerySegment Query -> Vector Value+    applySegment vec seg = join $ V.map (\x -> qQuerySegment seg qS{ curVal = x }) vec++-- | Runs the JSONPath Query also returning node locations+qQueryLocated :: Query -> QueryState -> String -> Vector (String,Value)+qQueryLocated Query{..} qS@QueryState{..} loc = case queryType of+  Root    -> foldl applySegment (V.singleton (loc,rootVal)) querySegments+  Current -> foldl applySegment (V.singleton (loc,curVal)) querySegments+  where+    applySegment :: Vector (String,Value) -> QuerySegment Query -> Vector (String,Value)+    applySegment vec seg = join $ V.map (\(location,cur) -> qQuerySegmentLocated seg qS{ curVal = cur } location) vec
+ src/Data/Aeson/JSONPath/Query/Segment.hs view
@@ -0,0 +1,92 @@+{-# LANGUAGE RecordWildCards #-}+module Data.Aeson.JSONPath.Query.Segment+  ( qQuerySegment+  , qQuerySegmentLocated+  )+  where++import Control.Monad (join)+import Data.Aeson    (Value)+import Data.Vector   (Vector)++import qualified Data.Aeson         as JSON+import qualified Data.Aeson.KeyMap  as KM+import qualified Data.Aeson.Key     as K+import qualified Data.Vector        as V++import Data.Aeson.JSONPath.Types+import Data.Aeson.JSONPath.Query.Selector++import Prelude++qQuerySegment :: QuerySegment Query -> QueryState -> Vector Value+qQuerySegment QuerySegment{..} qS@QueryState{..} = case segmentType of+  Child      -> joinAfterMap $ V.singleton curVal+  Descendant -> joinAfterMap $ allElemsRecursive curVal+  where+    joinAfterMap vec = join $ V.map (\cur -> qSegment segment qS{ curVal = cur }) vec++qQuerySegmentLocated :: QuerySegment Query -> QueryState-> String -> Vector (String, Value)+qQuerySegmentLocated QuerySegment{..} qS@QueryState{..} loc = case segmentType of+  Child      -> joinAfterMap $ V.singleton (loc,curVal)+  Descendant -> joinAfterMap $ allElemsRecursiveLocated (loc,curVal)+  where+    joinAfterMap vec = join $ V.map (\(location,cur) -> qSegmentLocated segment qS{ curVal = cur } location) vec++qSegment :: Segment Query -> QueryState -> Vector Value+qSegment (Bracketed sels) qS = V.concat $ map (`qSelector` qS) sels+qSegment (Dotted key) qS = qSelector (Name key) qS+qSegment WildcardSegment qS = qSelector WildcardSelector qS++qSegmentLocated :: Segment Query -> QueryState -> String -> Vector (String,Value)+qSegmentLocated (Bracketed sels) qS loc = V.concat $ map (\sel -> qSelectorLocated sel qS loc) sels+qSegmentLocated (Dotted key) qS loc = qSelectorLocated (Name key) qS loc+qSegmentLocated WildcardSegment qS loc = qSelectorLocated WildcardSelector qS loc++-- TODO: Looks kinda ugly, make it pretty <3+allElemsRecursive :: Value -> Vector Value+allElemsRecursive o@(JSON.Object obj) = V.concat [+    V.singleton o,+    V.concat $ map allElemsRecursive (KM.elems obj)+  ]+allElemsRecursive a@(JSON.Array arr) = V.concat [+    V.singleton a,+    V.concat $ map allElemsRecursive (V.toList arr)+  ]+allElemsRecursive _ = V.empty++-- TODO: Looks kinda ugly, make it pretty <3+allElemsRecursiveLocated :: (String,Value) -> Vector (String,Value)+allElemsRecursiveLocated (loc, o@(JSON.Object obj)) = V.concat [+    V.singleton (loc,o),+    V.concat $ zipWith (curry allElemsRecursiveLocated) keys (KM.elems obj)+  ]+  where+    keys = map (toPathKey loc) $ KM.keys obj+allElemsRecursiveLocated (loc, a@(JSON.Array arr)) = V.concat [+    V.singleton (loc,a),+    V.concat $ zipWith (curry allElemsRecursiveLocated) indices (V.toList arr)+  ]+  where+    indices = map (toPathIdx loc) [0..V.length arr - 1]+allElemsRecursiveLocated _ = V.empty++toPathKey :: String -> KM.Key -> String+toPathKey loc key = loc ++ "['" ++ escapeEscapees (K.toString key) ++ "']"+  where+    escapeEscapees :: String -> String+    escapeEscapees [] = []+    escapeEscapees (x:xs) = checkChar x ++ escapeEscapees xs+      where+        -- TODO: Do we need to escape unicode chars?+        checkChar '\\' = ['\\', '\\']+        checkChar '\'' = ['\\', '\'']+        checkChar '\b' = ['\\', 'b']+        checkChar '\r' = ['\\', 'r']+        checkChar '\t' = ['\\', 't']+        checkChar '\f' = ['\\', 'f']+        checkChar '\n' = ['\\', 'n']+        checkChar c = [c]++toPathIdx :: String -> Int -> String+toPathIdx loc idx = loc ++ "[" ++ show idx ++ "]"
+ src/Data/Aeson/JSONPath/Query/Selector.hs view
@@ -0,0 +1,139 @@+{-# LANGUAGE RecordWildCards #-}+module Data.Aeson.JSONPath.Query.Selector+  ( qSelector+  , qSelectorLocated+  )+  where++import Data.Aeson     (Value)+import Data.Vector    (Vector)+import Data.Text      (Text)++import qualified Data.Aeson            as JSON+import qualified Data.Aeson.KeyMap     as KM+import qualified Data.Aeson.Key        as K+import qualified Data.Text             as T+import qualified Data.Vector           as V++import Data.Aeson.JSONPath.Types+import Data.Aeson.JSONPath.Query.Filter++import Prelude++qSelector :: Selector Query -> QueryState -> Vector Value+qSelector (Name key) QueryState{curVal=(JSON.Object obj)} = maybe V.empty V.singleton $ KM.lookup (K.fromText key) obj+qSelector (Name _) _ = V.empty+qSelector (Index idx) QueryState{curVal=(JSON.Array arr)} = maybe V.empty V.singleton $ if idx >= 0 then (V.!?) arr idx else (V.!?) arr (idx + V.length arr)+qSelector (Index _) _ = V.empty+qSelector (ArraySlice startEndStep) QueryState{curVal=(JSON.Array arr) } = sliceArray startEndStep arr+qSelector (ArraySlice _) _ = V.empty+qSelector (Filter orExpr) qS = filterOrExpr orExpr qS+qSelector WildcardSelector QueryState{..} = case curVal of+    (JSON.Object obj) -> V.fromList $ KM.elems obj+    (JSON.Array arr)  -> arr+    _                 -> V.empty+++qSelectorLocated :: Selector Query -> QueryState -> String -> Vector (String,Value)+qSelectorLocated (Name key) QueryState{curVal=(JSON.Object obj)} loc = maybe V.empty (\x-> V.singleton (toPathKey loc key, x)) $ KM.lookup (K.fromText key) obj+qSelectorLocated (Name _) _ _ = V.empty+qSelectorLocated (Index idx) QueryState{curVal=(JSON.Array arr)} loc = maybe V.empty (\x-> V.singleton (newLocation, x)) $ (V.!?) arr (getIndex idx)+  where+    newLocation = loc ++ "[" ++ show (getIndex idx) ++ "]"+    getIndex i = if i >= 0 then i else i + V.length arr+qSelectorLocated (Index _) _ _ = V.empty+qSelectorLocated (ArraySlice (start,end,step)) QueryState{curVal=(JSON.Array arr)} loc = sliceArrayLocated (start,end,step) $ V.zip (V.fromList locs) arr+  where+    locs = [ loc ++ "[" ++ show i ++ "]" | i <- indices ]+    indices = [0..(V.length arr - 1)]+qSelectorLocated (ArraySlice _) _ _ = V.empty+qSelectorLocated (Filter orExpr) qS loc = filterOrExprLocated orExpr qS loc+qSelectorLocated WildcardSelector QueryState{..} loc = case curVal of+    (JSON.Object obj) -> V.fromList $ zip (locsWithKeys obj) (KM.elems obj)+    (JSON.Array arr)  -> V.zip (V.fromList (locsWithIdxs arr)) arr+    _                 -> V.empty+    where+      locsWithKeys obj = map (toPathKey loc . K.toText) (KM.keys obj)+      locsWithIdxs arr = map (\x -> loc ++ "[" ++ show x ++ "]") [0..(V.length arr)]+++sliceArray :: (Maybe Int, Maybe Int, Int) -> Vector Value -> Vector Value+sliceArray (start,end,step) vec =+  case compare step 0 of+    GT -> getSliceForward (maybe 0 normalize start) (maybe len normalize end) step vec+    LT -> getSliceReverse (maybe (len-1) normalize start) (maybe (-1) normalize end) step vec+    EQ -> V.empty+    where+      -- TODO: Looks kinda ugly, make it pretty <3+      len = V.length vec+      normalize i = if i >= 0 then i else len + i++      getSliceForward st en stp arr = loop lower V.empty+        where+          (lower,upper) = (min (max st 0) len, min (max en 0) len)++          loop i acc =+            if i < upper+              then loop (i+stp) $ V.snoc acc $ (V.!) arr (normalize i)+            else+              acc++      getSliceReverse st en stp arr = loop upper V.empty+        where+          (lower,upper) = (min (max en (-1)) (len-1), min (max st (-1)) (len-1))++          loop i acc =+            if lower < i+              then loop (i+stp) $ V.snoc acc $ (V.!) arr (normalize i)+            else+              acc+++sliceArrayLocated :: (Maybe Int, Maybe Int, Int) -> Vector (String,Value) -> Vector (String,Value)+sliceArrayLocated (start,end,step) vec =+  case compare step 0 of+    GT -> getSliceForward (maybe 0 normalize start) (maybe len normalize end) step vec+    LT -> getSliceReverse (maybe (len-1) normalize start) (maybe (-1) normalize end) step vec+    EQ -> V.empty+    where+      -- TODO: Looks kinda ugly, make it pretty <3+      len = V.length vec+      normalize i = if i >= 0 then i else len + i++      getSliceForward st en stp arr = loop lower V.empty+        where+          (lower,upper) = (min (max st 0) len, min (max en 0) len)++          loop i acc =+            if i < upper+              then loop (i+stp) $ V.snoc acc $ (V.!) arr (normalize i)+            else+              acc++      getSliceReverse st en stp arr = loop upper V.empty+        where+          (lower,upper) = (min (max en (-1)) (len-1), min (max st (-1)) (len-1))++          loop i acc =+            if lower < i+              then loop (i+stp) $ V.snoc acc $ (V.!) arr (normalize i)+            else+              acc+++toPathKey :: String -> Text -> String+toPathKey loc key = loc ++ "['" ++ escapeEscapees (T.unpack key) ++ "']"+  where+    escapeEscapees :: String -> String+    escapeEscapees [] = []+    escapeEscapees (x:xs) = checkChar x ++ escapeEscapees xs+      where+        -- TODO: Do we need to escape unicode chars?+        checkChar '\\' = ['\\', '\\']+        checkChar '\'' = ['\\', '\'']+        checkChar '\b' = ['\\', 'b']+        checkChar '\r' = ['\\', 'r']+        checkChar '\t' = ['\\', 't']+        checkChar '\f' = ['\\', 'f']+        checkChar '\n' = ['\\', 'n']+        checkChar c = [c]
− src/Data/Aeson/JSONPath/Query/Types.hs
@@ -1,139 +0,0 @@-{-# LANGUAGE DeriveLift #-}-{- |-Module      : Data.Aeson.JSONPath.Query.Types-Description : ADTs used internally-Copyright   : (c) 2024-2025 Taimoor Zaeem-License     : MIT-Maintainer  : Taimoor Zaeem <mtaimoorzaeem@gmail.com>-Stability   : Experimental-Portability : Portable--This module contains the data structures.--}-module Data.Aeson.JSONPath.Query.Types-  (Query (..)-  , QueryType (..)-  , Segment (..)-  , QuerySegment (..)-  , SegmentType (..)-  , Selector (..)-  , LogicalOrExpr (..)-  , LogicalAndExpr (..)-  , BasicExpr (..)-  , TestExpr-  , ComparisonExpr (..)-  , ComparisonOp (..)-  , Comparable(..)-  , SingularQuery (..)-  , SingularQueryType (..)-  , SingularQuerySegment (..)-  )-  where--import Data.Text                   (Text)-import Data.Scientific             (Scientific)-import Language.Haskell.TH.Syntax  (Lift)--import Prelude---- |-data QueryType -  = Root -  | Current-  deriving (Eq, Show, Lift)---- |-data Query = Query-  { queryType     :: QueryType-  , querySegments :: [QuerySegment]-  } deriving (Eq, Show, Lift)---- |-data SegmentType-  = Child-  | Descendant-  deriving (Eq, Show, Lift)---- |-data QuerySegment = QuerySegment-  { segmentType :: SegmentType-  , segment     :: Segment-  } deriving (Eq, Show, Lift)---- |-data Segment-  = Bracketed [Selector]-  | Dotted Text-  | WildcardSegment-  deriving (Eq, Show, Lift)---- |-data Selector-  = Name Text-  | Index Int-  | ArraySlice (Maybe Int, Maybe Int, Int)-  | Filter LogicalOrExpr-  | WildcardSelector-  deriving (Eq, Show, Lift)---- |-newtype LogicalOrExpr-  = LogicalOr [LogicalAndExpr]-  deriving (Eq, Show, Lift)---- |-newtype LogicalAndExpr-  = LogicalAnd [BasicExpr]-  deriving (Eq, Show, Lift)---- |-data BasicExpr-  = Paren LogicalOrExpr -- ( expr )-  | NotParen LogicalOrExpr -- not (expr)-  | Test TestExpr -- expr-  | NotTest TestExpr -- not expr-  | Comparison ComparisonExpr-  deriving (Eq, Show, Lift)---- |-type TestExpr = Query---- |-data ComparisonExpr-  = Comp Comparable ComparisonOp Comparable-  deriving (Eq, Show, Lift)---- |-data ComparisonOp-  = Less-  | LessOrEqual-  | Greater-  | GreaterOrEqual-  | Equal-  | NotEqual-  deriving (Eq, Show, Lift)---- |-data Comparable-  = CompLitString Text-  | CompLitNum Scientific-  | CompLitBool Bool-  | CompLitNull-  | CompSQ SingularQuery-  deriving (Eq, Show, Lift)---- |-data SingularQueryType = RootSQ | CurrentSQ-  deriving (Eq, Show, Lift)---- |-data SingularQuery = SingularQuery-  { singularQueryType     :: SingularQueryType-  , singularQuerySegments :: [SingularQuerySegment]-  } deriving (Eq, Show, Lift)---- |-data SingularQuerySegment-  = NameSQSeg Text-  | IndexSQSeg Int-  deriving (Eq, Show, Lift)
+ src/Data/Aeson/JSONPath/Types.hs view
@@ -0,0 +1,30 @@+{- |+Module      : Data.Aeson.JSONPath.Types+Description : Types related to JSONPath elements+Copyright   : (c) 2024-2025 Taimoor Zaeem+License     : MIT+Maintainer  : Taimoor Zaeem <mtaimoorzaeem@gmail.com>+Stability   : Experimental+Portability : Portable++This module contains all the data structures related to JSONPath+-}+module Data.Aeson.JSONPath.Types+  ( +    module Data.Aeson.JSONPath.Types.Query++  , module Data.Aeson.JSONPath.Types.Segment++  , module Data.Aeson.JSONPath.Types.Selector++  , module Data.Aeson.JSONPath.Types.Filter+  )+  where++import Data.Aeson.JSONPath.Types.Query++import Data.Aeson.JSONPath.Types.Segment++import Data.Aeson.JSONPath.Types.Selector++import Data.Aeson.JSONPath.Types.Filter
+ src/Data/Aeson/JSONPath/Types/Filter.hs view
@@ -0,0 +1,91 @@+{-# LANGUAGE DeriveLift #-}+module Data.Aeson.JSONPath.Types.Filter+  (LogicalOrExpr (..)+  , LogicalAndExpr (..)+  , BasicExpr (..)+  , TestExpr (..)+  , ComparisonExpr (..)+  , ComparisonOp (..)+  , Comparable (..)+  , Literal (..)+  , SingularQueryType (..)+  , SingularQuery (..)+  , SingularQuerySegment (..)+  )+  where++import Data.Text                   (Text)+import Data.Scientific             (Scientific)++import Language.Haskell.TH.Syntax  (Lift)++import Prelude++-- |+newtype LogicalOrExpr a+  = LogicalOr [LogicalAndExpr a]+  deriving (Eq, Show, Lift)++-- |+newtype LogicalAndExpr a+  = LogicalAnd [BasicExpr a]+  deriving (Eq, Show, Lift)++-- |+data BasicExpr a+  = Paren (LogicalOrExpr a) -- ( expr )+  | NotParen (LogicalOrExpr a) -- not (expr)+  | Test (TestExpr a) -- query+  | NotTest (TestExpr a) -- not query+  | Comparison ComparisonExpr+  deriving (Eq, Show, Lift)++-- |+newtype TestExpr a+  = FilterQuery a+  deriving (Eq, Show, Lift)++-- |+data ComparisonExpr+  = Comp Comparable ComparisonOp Comparable+  deriving (Eq, Show, Lift)++-- |+data ComparisonOp+  = Less+  | LessOrEqual+  | Greater+  | GreaterOrEqual+  | Equal+  | NotEqual+  deriving (Eq, Show, Lift)++-- |+data Comparable+  = CompLit Literal+  | CompSQ SingularQuery+  deriving (Eq, Show, Lift)++-- |+data Literal+  = LitString Text+  | LitNum Scientific+  | LitBool Bool+  | LitNull+  deriving (Eq, Show, Lift)++-- |+data SingularQueryType = RootSQ | CurrentSQ+  deriving (Eq, Show, Lift)++-- |+data SingularQuery = SingularQuery+  { singularQueryType     :: SingularQueryType+  , singularQuerySegments :: [SingularQuerySegment]+  } deriving (Eq, Show, Lift)++-- |+data SingularQuerySegment+  = NameSQSeg Text+  | IndexSQSeg Int+  deriving (Eq, Show, Lift)
+ src/Data/Aeson/JSONPath/Types/Query.hs view
@@ -0,0 +1,34 @@+{-# LANGUAGE DeriveLift #-}+module Data.Aeson.JSONPath.Types.Query+  ( Query (..)+  , QueryType (..)+  , QueryState (..)+  )+  where++import Data.Aeson  (Value)+import Data.Vector (Vector)++import Data.Aeson.JSONPath.Types.Segment (QuerySegment (..))+import Language.Haskell.TH.Syntax        (Lift)++import Prelude++-- |+data QueryState = QueryState+  { rootVal      :: Value+  , curVal       :: Value+  , executeQuery :: Query -> QueryState -> Vector Value+  }++-- |+data QueryType +  = Root +  | Current+  deriving (Eq, Show, Lift)++-- |+data Query = Query+  { queryType     :: QueryType+  , querySegments :: [QuerySegment Query]+  } deriving (Eq, Show, Lift)
+ src/Data/Aeson/JSONPath/Types/Segment.hs view
@@ -0,0 +1,32 @@+{-# LANGUAGE DeriveLift #-}+module Data.Aeson.JSONPath.Types.Segment+  (Segment (..)+  , QuerySegment (..)+  , SegmentType (..)+  )+  where++import Data.Aeson.JSONPath.Types.Selector (Selector (..))+import Data.Text                          (Text)+import Language.Haskell.TH.Syntax         (Lift)++import Prelude++-- |+data SegmentType+  = Child+  | Descendant+  deriving (Eq, Show, Lift)++-- |+data QuerySegment a = QuerySegment+  { segmentType :: SegmentType+  , segment     :: Segment a+  } deriving (Eq, Show, Lift)++-- |+data Segment a+  = Bracketed [Selector a]+  | Dotted Text+  | WildcardSegment+  deriving (Eq, Show, Lift)
+ src/Data/Aeson/JSONPath/Types/Selector.hs view
@@ -0,0 +1,19 @@+{-# LANGUAGE DeriveLift #-}+module Data.Aeson.JSONPath.Types.Selector+  (Selector (..))+  where++import Data.Aeson.JSONPath.Types.Filter (LogicalOrExpr (..))+import Data.Text                        (Text)+import Language.Haskell.TH.Syntax       (Lift)++import Prelude++-- |+data Selector a+  = Name Text+  | Index Int+  | ArraySlice (Maybe Int, Maybe Int, Int)+  | Filter (LogicalOrExpr a)+  | WildcardSelector+  deriving (Eq, Show, Lift)
− test/ComplianceSpec.hs
@@ -1,85 +0,0 @@-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE NamedFieldPuns #-}-module ComplianceSpec-  ( spec-  , TestSuite (..))-  where--import qualified Data.Aeson                    as JSON-import qualified Data.Vector                   as V-import qualified Text.ParserCombinators.Parsec as P--import Control.Monad              (mzero)-import Data.Aeson                 ((.:),(.:?),Value)-import Data.Aeson.JSONPath        (query)-import Data.Aeson.JSONPath.Parser (pQuery)-import Data.Either                (isLeft, fromRight)-import Data.Vector                (Vector)--import Test.Hspec-import Prelude--data TestSuite = TestSuite-  { tests :: [TestCase]-  } deriving (Show)--instance JSON.FromJSON TestSuite where-  parseJSON (JSON.Object o) =-    TestSuite-    <$> o .: "tests"--  parseJSON _ = mzero--data TestCase = TestCase-  { name       :: String-  , selector   :: String-  , document   :: Maybe Value-  , result     :: Maybe (Vector Value)-  , results    :: Maybe [Vector Value]-  , invalidSel :: Maybe Bool-  , tags       :: Maybe [String]-  } deriving (Show)--instance JSON.FromJSON TestCase where-  parseJSON (JSON.Object o) =-    TestCase-    <$> o .: "name"-    <*> o .: "selector"-    <*> o .:? "document"-    <*> o .:? "result"-    <*> o .:? "results"-    <*> o .:? "invalid_selector"-    <*> o .:? "tags"--  parseJSON _ = mzero--spec :: TestSuite -> Spec-spec TestSuite{tests} = do-  describe "compliance tests" $ do-    mapM_ runTestCase tests---runTestCase :: TestCase -> SpecWith ()--- skip function extension tests-runTestCase tc@TestCase{tags=Just xs, ..} =-  if (elem "function" xs)-    then xit name pending-  else-    runTestCase tc{tags=Nothing}---- invalid selector should not parse correctly-runTestCase TestCase{invalidSel=(Just True), ..} =-  it name $-    P.parse pQuery "" selector `shouldSatisfy` isLeft---- if result is deterministic (one json)-runTestCase TestCase{result=(Just r), document=(Just doc), ..} =-  it name $-    query selector doc `shouldBe` Right r---- if result is non-deterministic (any json from the list of results)-runTestCase TestCase{results=(Just rs), document=(Just doc), ..} = do-  it name $-    query selector doc `shouldSatisfy` (\x -> elem (fromRight V.empty x) rs)--runTestCase _ = pure ()
− test/LocatedSpec.hs
@@ -1,143 +0,0 @@-module LocatedSpec-  ( spec )-  where--import qualified Data.Aeson        as JSON-import qualified Data.Vector       as V--import Data.Aeson.JSONPath  (queryLocatedQQ, jsonPath)-import Data.Aeson.QQ.Simple (aesonQQ)-import Data.Vector          (Vector)-import Test.Hspec--import Prelude--getVector :: JSON.Value -> Vector JSON.Value-getVector (JSON.Array arr) = arr-getVector _ = V.empty---- taken from https://serdejsonpath.live/-rootDoc :: JSON.Value-rootDoc = [aesonQQ|{-    "store": {-      "books": [-        {-          "title": "Guns, Germs, and Steel",-          "author": "Jared Diamond",-          "category": "reference",-          "price": 24.99-        },-        {-          "title": "David Copperfield",-          "author": "Charles Dickens",-          "category": "fiction",-          "price": 12.99-        },-        {-          "title": "Moby Dick",-          "author": "Herman Melville",-          "category": "fiction",-          "price": 8.99-        },-        {-          "title": "Crime and Punishment",-          "author": "Fyodor Dostoevsky",-          "category": "fiction",-          "price": 19.99-        }-      ]-    }-  }|]---storeDoc :: JSON.Value-storeDoc = [aesonQQ|-  {-    "books": [-      {-        "title": "Guns, Germs, and Steel",-        "author": "Jared Diamond",-        "category": "reference",-        "price": 24.99-      },-      {-        "title": "David Copperfield",-        "author": "Charles Dickens",-        "category": "fiction",-        "price": 12.99-      },-      {-        "title": "Moby Dick",-        "author": "Herman Melville",-        "category": "fiction",-        "price": 8.99-      },-      {-        "title": "Crime and Punishment",-        "author": "Fyodor Dostoevsky",-        "category": "fiction",-        "price": 19.99-      }-    ]-  }|]--booksDoc :: JSON.Value-booksDoc = [aesonQQ| [-      {-        "title": "Guns, Germs, and Steel",-        "author": "Jared Diamond",-        "category": "reference",-        "price": 24.99-      },-      {-        "title": "David Copperfield",-        "author": "Charles Dickens",-        "category": "fiction",-        "price": 12.99-      },-      {-        "title": "Moby Dick",-        "author": "Herman Melville",-        "category": "fiction",-        "price": 8.99-      },-      {-        "title": "Crime and Punishment",-        "author": "Fyodor Dostoevsky",-        "category": "fiction",-        "price": 19.99-      }-  ]|]---books0Doc :: JSON.Value-books0Doc = [aesonQQ|[-      {-        "title": "Guns, Germs, and Steel",-        "author": "Jared Diamond",-        "category": "reference",-        "price": 24.99-      }-  ]|]---spec :: Spec-spec = do-  describe "test queryLocated" $ do-    it "returns root document when query is $" $-      queryLocatedQQ [jsonPath|$|] rootDoc `shouldBe` V.singleton ("$",rootDoc)--    it "returns store object when queryQQ is $.store" $-      queryLocatedQQ [jsonPath|$.store|] rootDoc `shouldBe` V.fromList [("$['store']",storeDoc)]--    it "returns store object when queryQQ is $['store']" $-      queryLocatedQQ [jsonPath|$['store']|] rootDoc `shouldBe` V.fromList [("$['store']",storeDoc)]--    it "returns books array when queryQQ is $.store.books" $-      queryLocatedQQ [jsonPath|$.store.books|] rootDoc `shouldBe` V.fromList [("$['store']['books']",booksDoc)]--    it "returns 0-index book item, $.store.books[0]" $-      queryLocatedQQ [jsonPath|$.store.books[0]|] rootDoc `shouldBe` V.zip (V.singleton "$['store']['books'][0]") (getVector books0Doc)--    it "returns 0-index book item, $.store.books[-4]" $-      queryLocatedQQ [jsonPath|$.store.books[-4]|] rootDoc `shouldBe` V.zip (V.singleton "$['store']['books'][0]") (getVector books0Doc)
− test/Main.hs
@@ -1,45 +0,0 @@-module Main-  ( main )-  where--import qualified Data.Aeson         as JSON-import qualified Test.Hspec         as HS-import qualified Data.Text.Encoding as T-import qualified Data.Text.IO       as TIO--import Data.Either                  (fromRight)--import qualified ParserSpec-import qualified QuerySpec-import qualified ComplianceSpec-import qualified LocatedSpec-import qualified Paths_aeson_jsonpath as Paths--import ComplianceSpec   (TestSuite (..))--import Test.Hspec.Runner-import Prelude--allSpecs :: Either String TestSuite -> Spec-allSpecs cts = do-  HS.describe "Run all tests" $ do-    ParserSpec.spec-    QuerySpec.spec-    ComplianceSpec.spec (fromRight TestSuite{tests=[]} cts)-    LocatedSpec.spec--readCtsFile :: FilePath -> IO (Either String TestSuite)-readCtsFile filePath = do-  contents <- TIO.readFile filePath-  return $ JSON.eitherDecodeStrict' $ T.encodeUtf8 contents--main :: IO ()-main = do-  file <- Paths.getDataFileName "test/cts.json"-  cts <- readCtsFile file-  summary <- hspecWithResult defaultConfig -    { configColorMode = ColorAuto-    } (allSpecs cts)-  -  putStrLn $ "Total tests: " ++ show (summaryExamples summary)-  putStrLn $ "Failures: "    ++ show (summaryFailures summary)
− test/ParserSpec.hs
@@ -1,442 +0,0 @@-module ParserSpec-  ( spec )-  where--import qualified Text.ParserCombinators.Parsec as P--import Data.Aeson.JSONPath.Parser       (pQuery)-import Data.Either                      (isLeft)--import Data.Aeson.JSONPath.Query.Types-import Test.Hspec-import Prelude--spec :: Spec-spec = do-  describe "Parse query string" $ do-    it "parses query: $" $-      P.parse pQuery "" "$"-      `shouldBe`-      Right (Query{queryType=Root,querySegments=[]})--    it "parses query: $.store" $-      P.parse pQuery "" "$.store"-      `shouldBe`-      Right Query {-        queryType = Root,-        querySegments = [QuerySegment {-          segmentType = Child,-          segment = Dotted "store"-        }]-      }--    it "parses query: $['store']" $-      P.parse pQuery "" "$['store']"-      `shouldBe`-      Right Query {-        queryType = Root,-        querySegments = [QuerySegment {-          segmentType = Child,-          segment = Bracketed [Name "store"]-        }]-      }--    it "parses query: $.store.books" $-      P.parse pQuery "" "$.store.books"-      `shouldBe`-      Right Query {-        queryType = Root,-        querySegments = [QuerySegment {-          segmentType = Child,-          segment = Dotted "store"-          }, QuerySegment {-          segmentType = Child,-          segment = Dotted "books"-        }]-      }--    it "parses query: $.store.books[0]" $-      P.parse pQuery "" "$.store.books[0]"-      `shouldBe`-      Right Query {-        queryType = Root,-        querySegments = [QuerySegment {-          segmentType = Child,-          segment = Dotted "store"-        }, QuerySegment {-          segmentType = Child,-          segment = Dotted "books"-        }, QuerySegment {-          segmentType = Child,-          segment = Bracketed [Index 0]-        }]-      }--    it "parses query: $.store.books[0,2]" $-      P.parse pQuery "" "$.store.books[0,2]"-      `shouldBe`-      Right Query {-        queryType = Root,-        querySegments = [QuerySegment {-          segmentType = Child,-          segment = Dotted "store"-        }, QuerySegment {-          segmentType = Child,-          segment = Dotted "books"-        }, QuerySegment {-          segmentType = Child,-          segment = Bracketed [Index 0, Index 2]-        }]-      }--    it "parses query: $.store.books[1:3]" $-      P.parse pQuery "" "$.store.books[1:3]"-      `shouldBe`-      Right Query {-        queryType = Root,-        querySegments = [QuerySegment {-          segmentType = Child,-          segment = Dotted "store"-        }, QuerySegment {-          segmentType = Child,-          segment = Dotted "books"-        }, QuerySegment {-          segmentType = Child,-          segment = Bracketed [ArraySlice (Just 1, Just 3, 1)]-        }]-      }--    it "parses query: $.store.books[1:4:2]" $-      P.parse pQuery "" "$.store.books[1:4:2]"-      `shouldBe`-      Right Query {-        queryType = Root,-        querySegments = [QuerySegment {-          segmentType = Child,-          segment = Dotted "store"-        }, QuerySegment {-          segmentType = Child,-          segment = Dotted "books"-        }, QuerySegment {-          segmentType = Child,-          segment = Bracketed [ArraySlice (Just 1, Just 4, 2)]-        }]-      }--    it "parses query: $.store.books[-1:-4:-2]" $-      P.parse pQuery "" "$.store.books[-1:-4:-2]"-      `shouldBe`-      Right Query {-        queryType = Root,-        querySegments = [QuerySegment {-          segmentType = Child,-          segment = Dotted "store"-        }, QuerySegment {-          segmentType = Child,-          segment = Dotted "books"-        }, QuerySegment {-          segmentType = Child,-          segment = Bracketed [ArraySlice (Just (-1), Just (-4), (-2))]-        }]-      }--    it "parses query: $.store.books[1:3, 0, 1]" $-      P.parse pQuery "" "$.store.books[1:3, 0, 1]"-      `shouldBe`-      Right Query {-        queryType = Root,-        querySegments = [QuerySegment {-          segmentType = Child,-          segment = Dotted "store"-        }, QuerySegment {-          segmentType = Child,-          segment = Dotted "books"-        }, QuerySegment {-          segmentType = Child,-          segment = Bracketed [ArraySlice (Just 1, Just 3, 1), Index 0, Index 1]-        }]-      }--    it "parses query: $.*" $-      P.parse pQuery "" "$.*" -      `shouldBe` -      Right Query {-        queryType = Root,-        querySegments = [QuerySegment {-          segmentType = Child,-          segment = WildcardSegment-        }]-      }--    it "parses query: $[*]" $-      P.parse pQuery "" "$[*]"-      `shouldBe`-      Right Query {-        queryType = Root,-        querySegments = [QuerySegment {-          segmentType = Child,-          segment = Bracketed [WildcardSelector]-        }]-      }--    it "parses query: $..*" $-      P.parse pQuery "" "$..*"-      `shouldBe`-      Right Query {-        queryType = Root,-        querySegments = [QuerySegment {-          segmentType = Descendant,-          segment = WildcardSegment-        }]-      }--    it "parses query: $..[*]" $-      P.parse pQuery "" "$..[*]"-      `shouldBe` -      Right Query {-        queryType = Root,-        querySegments = [QuerySegment {-          segmentType = Descendant,-          segment = Bracketed [WildcardSelector]-        }]-      }--    it "fails with $.1startsWithNum" $-      P.parse pQuery "" "$.1startsWithNum"-      `shouldSatisfy` isLeft--    it "parses query $.©®±×÷Ωπ•€→∀∃∈≠≤≥✓λ" $-      P.parse pQuery "" "$.©®±×÷Ωπ•€→∀∃∈≠≤≥✓λ"-      `shouldBe`-      Right Query {-        queryType = Root,-        querySegments = [QuerySegment {-          segmentType = Child,-          segment = Dotted "©®±×÷Ωπ•€→∀∃∈≠≤≥✓λ"-        }]-      }--    it "parses query: $._" $-      P.parse pQuery "" "$._"-      `shouldBe`-      Right Query {-        queryType = Root,-        querySegments = [QuerySegment {-          segmentType = Child,-          segment = Dotted "_"-        }]-      }--    it "parses query: $.underscore_key" $-      P.parse pQuery "" "$.underscore_key"-      `shouldBe`-      Right Query {-        queryType = Root,-        querySegments = [QuerySegment {-          segmentType = Child,-          segment = Dotted "underscore_key"-        }]-      }--    it "parses query: $[0,TAB/LINEFEED/RETURN/SPACE1]" $-      P.parse pQuery "" "$[0,\n\t\r 1]"-      `shouldBe`-      Right Query {-        queryType = Root,-        querySegments = [QuerySegment {-          segmentType = Child,-          segment = Bracketed [Index 0, Index 1]-        }]-      }--    describe "parses JSPFilter Query" $ do-      it "$[?@.category == 'reference']" $-        P.parse pQuery "" "$[?@.category == 'reference']"-        `shouldBe`-        Right Query {-          queryType = Root,-          querySegments = [QuerySegment {-            segmentType = Child,-            segment = Bracketed [Filter (LogicalOr [LogicalAnd [Comparison (Comp (CompSQ SingularQuery {-              singularQueryType = CurrentSQ,-              singularQuerySegments = [NameSQSeg "category"]-            }) Equal (CompLitString "reference"))]])]-          }]-        }--      it "test expr: $..books[?@.price].title" $-        P.parse pQuery "" "$..books[?@.price].title"-        `shouldBe`-        Right Query {-          queryType = Root,-          querySegments = [QuerySegment {-            segmentType = Descendant,-            segment = Dotted "books"-          }, QuerySegment {-            segmentType = Child,-            segment = Bracketed [Filter (LogicalOr [LogicalAnd [Test Query {-              queryType = Current,-              querySegments = [QuerySegment {-                segmentType = Child,-                segment = Dotted "price"-              }]-            }]])]-          }, QuerySegment {-            segmentType = Child,-            segment = Dotted "title"-          }]-        }--      it "and expr: $[?@.price < 20 && @.price > 10]" $-        P.parse pQuery "" "$[?@.price < 20 && @.price > 10]" -        `shouldBe`-        Right Query {-          queryType = Root,-          querySegments = [QuerySegment {-            segmentType = Child,-            segment = Bracketed [Filter (LogicalOr [LogicalAnd [Comparison (Comp (CompSQ SingularQuery {-              singularQueryType = CurrentSQ,-              singularQuerySegments = [NameSQSeg "price"]-            }) Less (CompLitNum 20.0)), Comparison (Comp (CompSQ SingularQuery {-              singularQueryType = CurrentSQ,-              singularQuerySegments = [NameSQSeg "price"]-            }) Greater (CompLitNum 10.0))]])]-          }]-        }--      it "or expr: $[?@.price < 20 || @.price > 10]" $-        P.parse pQuery "" "$[?@.price < 20 || @.price > 10]"-        `shouldBe`-        Right Query {-          queryType = Root,-          querySegments = [QuerySegment {-            segmentType = Child,-            segment = Bracketed [Filter (LogicalOr [LogicalAnd [Comparison (Comp (CompSQ SingularQuery {-              singularQueryType = CurrentSQ,-              singularQuerySegments = [NameSQSeg "price"]-            }) Less (CompLitNum 20.0))], LogicalAnd [Comparison (Comp (CompSQ SingularQuery {-              singularQueryType = CurrentSQ,-              singularQuerySegments = [NameSQSeg "price"]-            }) Greater (CompLitNum 10.0))]])]-          }]-        }--      it "root filter: $..books[?$.price].title" $-        P.parse pQuery "" "$..books[?$.price].title"-        `shouldBe`-        Right Query {-          queryType = Root,-          querySegments = [QuerySegment {-            segmentType = Descendant,-            segment = Dotted "books"-          }, QuerySegment {-            segmentType = Child,-            segment = Bracketed [Filter (LogicalOr [LogicalAnd [Test Query {-              queryType = Root,-              querySegments = [QuerySegment {-                segmentType = Child,-                segment = Dotted "price"-              }]-            }]])]-          }, QuerySegment {-            segmentType = Child,-            segment = Dotted "title"-          }]-        }--      it "not expr: $[?!(@.price < 20 && @.price > 10)]" $-        P.parse pQuery "" "$[?!(@.price < 20 && @.price > 10)]" -        `shouldBe`-        Right Query {-          queryType = Root,-          querySegments = [QuerySegment {-            segmentType = Child,-            segment = Bracketed [Filter (LogicalOr [LogicalAnd [NotParen (LogicalOr [LogicalAnd [Comparison (Comp (CompSQ SingularQuery {-              singularQueryType = CurrentSQ,-              singularQuerySegments = [NameSQSeg "price"]-            })  Less (CompLitNum 20.0)), Comparison (Comp (CompSQ SingularQuery {-              singularQueryType = CurrentSQ,-              singularQuerySegments = [NameSQSeg "price"]-            }) Greater (CompLitNum 10.0))]])]])]-          }]-        }--      it "scientific: $.store.books[?@.price < -1e20]" $-        P.parse pQuery "" "$.store.books[?@['price'] < -1e20]"-        `shouldBe`-        Right Query {-          queryType = Root,-          querySegments = [QuerySegment {-            segmentType = Child,-            segment = Dotted "store"-          }, QuerySegment {-            segmentType = Child,-            segment = Dotted "books"-          }, QuerySegment {-            segmentType = Child,-            segment = Bracketed [Filter (LogicalOr [LogicalAnd [Comparison (Comp (CompSQ SingularQuery {-              singularQueryType = CurrentSQ,-              singularQuerySegments = [NameSQSeg "price"]-            }) Less (CompLitNum (-1.0e20)))]])]-          }]-        }--      it "double: $.store.books[?@.price < 0.01]" $-        P.parse pQuery "" "$.store.books[?@['price'] < 0.01]"-        `shouldBe`-        Right Query {-          queryType = Root,-          querySegments = [QuerySegment {-            segmentType = Child,-            segment = Dotted "store"-          }, QuerySegment {-            segmentType = Child,-            segment = Dotted "books"-          }, QuerySegment {-            segmentType = Child,-            segment = Bracketed [Filter (LogicalOr [LogicalAnd [Comparison (Comp (CompSQ SingularQuery {-              singularQueryType = CurrentSQ,-              singularQuerySegments = [NameSQSeg "price"]-            }) Less (CompLitNum (1.0e-2)))]])]-          }]-        }--      it "bool: $.store.books[?@.is_available == true]" $-        P.parse pQuery "" "$.store.books[?@.is_available == true]"-        `shouldBe`-        Right Query {-          queryType = Root,-          querySegments = [QuerySegment {-            segmentType = Child,-            segment = Dotted "store"-          }, QuerySegment {-            segmentType = Child,-            segment = Dotted "books"-          }, QuerySegment {-            segmentType = Child,-            segment = Bracketed [Filter (LogicalOr [LogicalAnd [Comparison (Comp (CompSQ SingularQuery {-              singularQueryType = CurrentSQ,-              singularQuerySegments = [NameSQSeg "is_available"]-            }) Equal (CompLitBool True))]])]-          }]-        }--      it "null: $.store.books[?@.is_available == null]" $-        P.parse pQuery "" "$.store.books[?@.is_available == null]"-        `shouldBe`-        Right Query {-          queryType = Root,-          querySegments = [QuerySegment {-            segmentType = Child,-            segment = Dotted "store"-          }, QuerySegment {-            segmentType = Child,-            segment = Dotted "books"-          }, QuerySegment {-            segmentType = Child,-            segment = Bracketed [Filter (LogicalOr [LogicalAnd [Comparison (Comp (CompSQ SingularQuery {-              singularQueryType = CurrentSQ,-              singularQuerySegments = [NameSQSeg "is_available"]-            }) Equal CompLitNull)]])]-          }]-        }
− test/QuerySpec.hs
@@ -1,342 +0,0 @@-module QuerySpec-  ( spec )-  where--import qualified Data.Aeson        as JSON-import qualified Data.Vector       as V--import Data.Aeson.JSONPath  (queryQQ, jsonPath)-import Data.Aeson.QQ.Simple (aesonQQ)-import Data.Vector          (Vector)-import Test.Hspec--import Prelude--getVector :: JSON.Value -> Vector JSON.Value-getVector (JSON.Array arr) = arr-getVector _ = V.empty---- taken from https://serdejsonpath.live/-rootDoc :: JSON.Value-rootDoc = [aesonQQ|{-    "store": {-      "books": [-        {-          "title": "Guns, Germs, and Steel",-          "author": "Jared Diamond",-          "category": "reference",-          "price": 24.99-        },-        {-          "title": "David Copperfield",-          "author": "Charles Dickens",-          "category": "fiction",-          "price": 12.99-        },-        {-          "title": "Moby Dick",-          "author": "Herman Melville",-          "category": "fiction",-          "price": 8.99-        },-        {-          "title": "Crime and Punishment",-          "author": "Fyodor Dostoevsky",-          "category": "fiction",-          "price": 19.99-        }-      ]-    }-  }|]---storeDoc :: JSON.Value-storeDoc = [aesonQQ|-  {-    "books": [-      {-        "title": "Guns, Germs, and Steel",-        "author": "Jared Diamond",-        "category": "reference",-        "price": 24.99-      },-      {-        "title": "David Copperfield",-        "author": "Charles Dickens",-        "category": "fiction",-        "price": 12.99-      },-      {-        "title": "Moby Dick",-        "author": "Herman Melville",-        "category": "fiction",-        "price": 8.99-      },-      {-        "title": "Crime and Punishment",-        "author": "Fyodor Dostoevsky",-        "category": "fiction",-        "price": 19.99-      }-    ]-  }|]--booksDoc :: JSON.Value-booksDoc = [aesonQQ| [-      {-        "title": "Guns, Germs, and Steel",-        "author": "Jared Diamond",-        "category": "reference",-        "price": 24.99-      },-      {-        "title": "David Copperfield",-        "author": "Charles Dickens",-        "category": "fiction",-        "price": 12.99-      },-      {-        "title": "Moby Dick",-        "author": "Herman Melville",-        "category": "fiction",-        "price": 8.99-      },-      {-        "title": "Crime and Punishment",-        "author": "Fyodor Dostoevsky",-        "category": "fiction",-        "price": 19.99-      }-  ]|]---books0Doc :: JSON.Value-books0Doc = [aesonQQ|[-      {-        "title": "Guns, Germs, and Steel",-        "author": "Jared Diamond",-        "category": "reference",-        "price": 24.99-      }-  ]|]--books0And2Doc :: JSON.Value-books0And2Doc = [aesonQQ|[-      {-        "title": "Guns, Germs, and Steel",-        "author": "Jared Diamond",-        "category": "reference",-        "price": 24.99-      },-      {-        "title": "Moby Dick",-        "author": "Herman Melville",-        "category": "fiction",-        "price": 8.99-      }-  ]|]--books1To3Doc :: JSON.Value-books1To3Doc = [aesonQQ|[-      {-        "title": "David Copperfield",-        "author": "Charles Dickens",-        "category": "fiction",-        "price": 12.99-      },-      {-        "title": "Moby Dick",-        "author": "Herman Melville",-        "category": "fiction",-        "price": 8.99-      }-  ]|]--books1To3And0And1Doc :: JSON.Value-books1To3And0And1Doc = [aesonQQ|[-      {-        "title": "David Copperfield",-        "author": "Charles Dickens",-        "category": "fiction",-        "price": 12.99-      },-      {-        "title": "Moby Dick",-        "author": "Herman Melville",-        "category": "fiction",-        "price": 8.99-      },-      {-        "title": "Guns, Germs, and Steel",-        "author": "Jared Diamond",-        "category": "reference",-        "price": 24.99-      },-      {-        "title": "David Copperfield",-        "author": "Charles Dickens",-        "category": "fiction",-        "price": 12.99-      }-  ]|]--lessThanPrice20Books :: JSON.Value-lessThanPrice20Books = [aesonQQ| [-      {-        "title": "David Copperfield",-        "author": "Charles Dickens",-        "category": "fiction",-        "price": 12.99-      },-      {-        "title": "Moby Dick",-        "author": "Herman Melville",-        "category": "fiction",-        "price": 8.99-      },-      {-        "title": "Crime and Punishment",-        "author": "Fyodor Dostoevsky",-        "category": "fiction",-        "price": 19.99-      }-  ]|]--alphaArr :: JSON.Value-alphaArr = [aesonQQ| ["a","b","c","d","e","f","g"] |]--fgArr :: JSON.Value-fgArr = [aesonQQ| ["f","g"] |]--bdArr :: JSON.Value-bdArr = [aesonQQ| ["b","d"] |]--fdArr :: JSON.Value-fdArr = [aesonQQ| ["f","d"] |]--gfedcbaArr :: JSON.Value-gfedcbaArr = [aesonQQ| ["g","f","e","d","c","b","a"] |]--rfcExample1 :: JSON.Value-rfcExample1 = [aesonQQ| {-    "o": {"j": 1, "k": 2},-    "a": [5, 3, [{"j": 4}, {"k": 6}]]-  } |]--rfcExample1Desc :: JSON.Value-rfcExample1Desc = [aesonQQ| [-    [5, 3, [{"j": 4}, {"k": 6}]],-    {"j": 1, "k": 2},-    5,-    3,-    [{"j": 4}, {"k": 6}],-    {"j": 4},-    {"k": 6},-    4,-    6,-    1,-    2-  ]|]--boolsAndNulls :: JSON.Value-boolsAndNulls = [aesonQQ| [-    { "a": true },-    { "a": false },-    { "a": null }-  ]|]---boolsAndNullsA :: JSON.Value-boolsAndNullsA = [aesonQQ| [{ "a": true }] |]--boolsAndNullsB :: JSON.Value-boolsAndNullsB = [aesonQQ| [{ "a": false }] |]--boolsAndNullsC :: JSON.Value-boolsAndNullsC = [aesonQQ| [{ "a": null }] |]--spec :: Spec-spec = do-  describe "test query" $ do-    it "returns root document when query is $" $-      queryQQ [jsonPath|$|] rootDoc `shouldBe` V.singleton rootDoc--    it "returns store object when queryQQ is $.store" $-      queryQQ [jsonPath|$.store|] rootDoc `shouldBe` V.singleton storeDoc--    it "returns store object when queryQQ is $['store']" $-      queryQQ [jsonPath|$['store']|] rootDoc `shouldBe` V.singleton storeDoc--    it "returns books array when queryQQ is $.store.books" $-      queryQQ [jsonPath|$.store.books|] rootDoc `shouldBe` V.singleton booksDoc--    it "returns 0-index book item when queryQQ is $.store.books[0]" $-      queryQQ [jsonPath|$.store.books[0]|] rootDoc `shouldBe` getVector books0Doc--    it "returns 0-index book item when queryQQ is $.store.books[-4]" $-      queryQQ [jsonPath|$.store.books[-4]|] rootDoc `shouldBe` getVector books0Doc--    it "returns 0,2-index item when queryQQ is $.store.books[0,2]" $-      queryQQ [jsonPath|$.store.books[0,2]|] rootDoc `shouldBe` getVector books0And2Doc--    it "returns 1To3-index when queryQQ is $.store.books[1:3]" $-      queryQQ [jsonPath|$.store.books[1:3]|] rootDoc `shouldBe` getVector books1To3Doc--    it "returns 1To3-index and 0,1-index when queryQQ is $.store.books[1:3,0,1]" $-      queryQQ [jsonPath|$.store.books[1:3,0,1]|] rootDoc `shouldBe` getVector books1To3And0And1Doc--    it "returns slice with queryQQ $[5:]" $-      queryQQ [jsonPath|$[5:]|] alphaArr `shouldBe` getVector fgArr--    it "returns slice with queryQQ $[1:5:2]" $-      queryQQ [jsonPath|$[1:5:2]|] alphaArr `shouldBe` getVector bdArr--    it "returns slice with queryQQ $[5:1:-2]" $-      queryQQ [jsonPath|$[5:1:-2]|] alphaArr `shouldBe` getVector fdArr--    it "returns slice with queryQQ $[::-1]" $-      queryQQ [jsonPath|$[::-1]|] alphaArr `shouldBe` getVector gfedcbaArr--    it "returns root with queryQQ $.*" $-      queryQQ [jsonPath|$.*|] rootDoc `shouldBe` V.singleton storeDoc--    it "returns root with queryQQ $[*]" $-      queryQQ [jsonPath|$[*]|] rootDoc `shouldBe` V.singleton storeDoc--    it "returns descendants with queryQQ $..*" $-      queryQQ [jsonPath|$..*|] rfcExample1 `shouldBe` getVector rfcExample1Desc--    it "returns descendants with queryQQ $..[*]" $-      queryQQ [jsonPath|$..[*]|] rfcExample1 `shouldBe` getVector rfcExample1Desc--    it "returns with filtering: number comparison" $-      queryQQ [jsonPath|$.store.books[?@.price < 20]|] rootDoc-      `shouldBe` getVector lessThanPrice20Books--    it "returns with filtering: not operator" $-      queryQQ [jsonPath|$.store.books[?!(@.price < 20)]|] rootDoc-      `shouldBe` getVector books0Doc--    it "returns with filtering: true value" $-      queryQQ [jsonPath|$[?@.a == true]|] boolsAndNulls-      `shouldBe` getVector boolsAndNullsA--    it "returns with filtering: false value" $-      queryQQ [jsonPath|$[?@.a == false]|] boolsAndNulls-      `shouldBe` getVector boolsAndNullsB--    it "returns with filtering: null value" $-      queryQQ [jsonPath|$[?@.a == null]|] boolsAndNulls-      `shouldBe` getVector boolsAndNullsC--    it "returns with filtering: string comparison" $-      queryQQ [jsonPath|$.store.books[?@.author == 'Jared Diamond']|] rootDoc-      `shouldBe` getVector books0Doc--    it "returns with filtering: test expression" $-      queryQQ [jsonPath|$.store.books[?@.author]|] rootDoc-      `shouldBe` getVector booksDoc--    it "returns with filtering: test expr gives empty with non-existent key" $-      queryQQ [jsonPath|$.store.books[?@.not_here]|] rootDoc-      `shouldBe` V.empty
+ test/compliance/ComplianceSpec.hs view
@@ -0,0 +1,93 @@+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE NamedFieldPuns #-}+module ComplianceSpec+  ( spec+  , TestSuite (..))+  where++import qualified Data.Aeson                    as JSON+import qualified Data.Vector                   as V+import qualified Text.ParserCombinators.Parsec as P++import Control.Monad              (mzero)+import Data.Aeson                 ((.:),(.:?),Value)+import Data.Aeson.JSONPath        (query, queryLocated)+import Data.Aeson.JSONPath.Parser (pQuery)+import Data.Either                (isLeft, fromRight)+import Data.Vector                (Vector)++import Test.Hspec+import Prelude++newtype TestSuite = TestSuite+  { tests :: [TestCase]+  } deriving (Show)++instance JSON.FromJSON TestSuite where+  parseJSON (JSON.Object o) =+    TestSuite+    <$> o .: "tests"++  parseJSON _ = mzero++data TestCase = TestCase+  { name         :: String+  , selector     :: String+  , document     :: Maybe Value+  , result       :: Maybe (Vector Value)+  , results      :: Maybe [Vector Value]+  , resultPaths  :: Maybe (Vector String)+  , resultsPaths :: Maybe [Vector String]+  , invalidSel   :: Maybe Bool+  , tags         :: Maybe [String]+  } deriving (Show)++instance JSON.FromJSON TestCase where+  parseJSON (JSON.Object o) =+    TestCase+    <$> o .: "name"+    <*> o .: "selector"+    <*> o .:? "document"+    <*> o .:? "result"+    <*> o .:? "results"+    <*> o .:? "result_paths"+    <*> o .:? "results_paths"+    <*> o .:? "invalid_selector"+    <*> o .:? "tags"++  parseJSON _ = mzero++spec :: TestSuite -> Spec+spec TestSuite{tests} = do+  describe "compliance tests" $ do+    mapM_ runTestCase tests+++runTestCase :: TestCase -> SpecWith ()+-- skip function extension tests+runTestCase tc@TestCase{tags=Just xs, ..} =+  if "function" `elem` xs+    then xit name pending+  else+    runTestCase tc{tags=Nothing}++-- invalid selector should not parse correctly+runTestCase TestCase{invalidSel=(Just True), ..} =+  it name $+    P.parse pQuery "" selector `shouldSatisfy` isLeft++-- if result is deterministic (one json)+runTestCase TestCase{result=(Just r), resultPaths=(Just rp), document=(Just doc), ..} =+  it name $ do+    query selector doc `shouldBe` Right r+    queryLocated selector doc `shouldBe` Right (V.zip rp r)++-- if result is non-deterministic (any json from the list of results)+runTestCase TestCase{results=(Just rs), resultsPaths=(Just rsp), document=(Just doc), ..} = do+  it name $ do+    query selector doc `shouldSatisfy` (\x -> fromRight V.empty x `elem` rs)+    queryLocated selector doc `shouldSatisfy` (\x -> fromRight V.empty x `elem` vecList)+    where+      vecList = [ V.zip rp r | rp <- rsp, r <- rs]++runTestCase _ = pure ()
+ test/compliance/Main.hs view
@@ -0,0 +1,39 @@+module Main+  ( main )+  where++import qualified Data.Aeson         as JSON+import qualified Test.Hspec         as HS+import qualified Data.Text.Encoding as T+import qualified Data.Text.IO       as TIO++import Data.Either                  (fromRight)++import qualified ComplianceSpec+import qualified Paths_aeson_jsonpath as Paths++import ComplianceSpec   (TestSuite (..))++import Test.Hspec.Runner+import Prelude++compliance :: Either String TestSuite -> Spec+compliance cts = do+  HS.describe "Run compliance tests" $+    ComplianceSpec.spec (fromRight TestSuite{tests=[]} cts)++readCtsFile :: FilePath -> IO (Either String TestSuite)+readCtsFile filePath = do+  contents <- TIO.readFile filePath+  return $ JSON.eitherDecodeStrict' $ T.encodeUtf8 contents++main :: IO ()+main = do+  file <- Paths.getDataFileName "jsonpath-compliance-test-suite/cts.json"+  cts <- readCtsFile file+  summary <- hspecWithResult defaultConfig +    { configColorMode = ColorAuto+    } (compliance cts)+  +  putStrLn $ "Total tests: " ++ show (summaryExamples summary)+  putStrLn $ "Failures: "    ++ show (summaryFailures summary)
− test/cts.json
@@ -1,10941 +0,0 @@-{-  "description": "JSONPath Compliance Test Suite. This file is autogenerated, do not edit.",-  "tests": [-    {-      "name": "basic, root",-      "selector": "$",-      "document": [-        "first",-        "second"-      ],-      "result": [-        [-          "first",-          "second"-        ]-      ]-    },-    {-      "name": "basic, no leading whitespace",-      "selector": " $",-      "invalid_selector": true,-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "basic, no trailing whitespace",-      "selector": "$ ",-      "invalid_selector": true,-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "basic, name shorthand",-      "selector": "$.a",-      "document": {-        "a": "A",-        "b": "B"-      },-      "result": [-        "A"-      ]-    },-    {-      "name": "basic, name shorthand, extended unicode ☺",-      "selector": "$.☺",-      "document": {-        "☺": "A",-        "b": "B"-      },-      "result": [-        "A"-      ]-    },-    {-      "name": "basic, name shorthand, underscore",-      "selector": "$._",-      "document": {-        "_": "A",-        "_foo": "B"-      },-      "result": [-        "A"-      ]-    },-    {-      "name": "basic, name shorthand, symbol",-      "selector": "$.&",-      "invalid_selector": true-    },-    {-      "name": "basic, name shorthand, number",-      "selector": "$.1",-      "invalid_selector": true-    },-    {-      "name": "basic, name shorthand, absent data",-      "selector": "$.c",-      "document": {-        "a": "A",-        "b": "B"-      },-      "result": []-    },-    {-      "name": "basic, name shorthand, array data",-      "selector": "$.a",-      "document": [-        "first",-        "second"-      ],-      "result": []-    },-    {-      "name": "basic, wildcard shorthand, object data",-      "selector": "$.*",-      "document": {-        "a": "A",-        "b": "B"-      },-      "results": [-        [-          "A",-          "B"-        ],-        [-          "B",-          "A"-        ]-      ]-    },-    {-      "name": "basic, wildcard shorthand, array data",-      "selector": "$.*",-      "document": [-        "first",-        "second"-      ],-      "result": [-        "first",-        "second"-      ]-    },-    {-      "name": "basic, wildcard selector, array data",-      "selector": "$[*]",-      "document": [-        "first",-        "second"-      ],-      "result": [-        "first",-        "second"-      ]-    },-    {-      "name": "basic, wildcard shorthand, then name shorthand",-      "selector": "$.*.a",-      "document": {-        "x": {-          "a": "Ax",-          "b": "Bx"-        },-        "y": {-          "a": "Ay",-          "b": "By"-        }-      },-      "results": [-        [-          "Ax",-          "Ay"-        ],-        [-          "Ay",-          "Ax"-        ]-      ]-    },-    {-      "name": "basic, multiple selectors",-      "selector": "$[0,2]",-      "document": [-        0,-        1,-        2,-        3,-        4,-        5,-        6,-        7,-        8,-        9-      ],-      "result": [-        0,-        2-      ]-    },-    {-      "name": "basic, multiple selectors, space instead of comma",-      "selector": "$[0 2]",-      "invalid_selector": true,-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "basic, selector, leading comma",-      "selector": "$[,0]",-      "invalid_selector": true-    },-    {-      "name": "basic, selector, trailing comma",-      "selector": "$[0,]",-      "invalid_selector": true-    },-    {-      "name": "basic, multiple selectors, name and index, array data",-      "selector": "$['a',1]",-      "document": [-        0,-        1,-        2,-        3,-        4,-        5,-        6,-        7,-        8,-        9-      ],-      "result": [-        1-      ]-    },-    {-      "name": "basic, multiple selectors, name and index, object data",-      "selector": "$['a',1]",-      "document": {-        "a": 1,-        "b": 2-      },-      "result": [-        1-      ]-    },-    {-      "name": "basic, multiple selectors, index and slice",-      "selector": "$[1,5:7]",-      "document": [-        0,-        1,-        2,-        3,-        4,-        5,-        6,-        7,-        8,-        9-      ],-      "result": [-        1,-        5,-        6-      ]-    },-    {-      "name": "basic, multiple selectors, index and slice, overlapping",-      "selector": "$[1,0:3]",-      "document": [-        0,-        1,-        2,-        3,-        4,-        5,-        6,-        7,-        8,-        9-      ],-      "result": [-        1,-        0,-        1,-        2-      ]-    },-    {-      "name": "basic, multiple selectors, duplicate index",-      "selector": "$[1,1]",-      "document": [-        0,-        1,-        2,-        3,-        4,-        5,-        6,-        7,-        8,-        9-      ],-      "result": [-        1,-        1-      ]-    },-    {-      "name": "basic, multiple selectors, wildcard and index",-      "selector": "$[*,1]",-      "document": [-        0,-        1,-        2,-        3,-        4,-        5,-        6,-        7,-        8,-        9-      ],-      "result": [-        0,-        1,-        2,-        3,-        4,-        5,-        6,-        7,-        8,-        9,-        1-      ]-    },-    {-      "name": "basic, multiple selectors, wildcard and name",-      "selector": "$[*,'a']",-      "document": {-        "a": "A",-        "b": "B"-      },-      "results": [-        [-          "A",-          "B",-          "A"-        ],-        [-          "B",-          "A",-          "A"-        ]-      ]-    },-    {-      "name": "basic, multiple selectors, wildcard and slice",-      "selector": "$[*,0:2]",-      "document": [-        0,-        1,-        2,-        3,-        4,-        5,-        6,-        7,-        8,-        9-      ],-      "result": [-        0,-        1,-        2,-        3,-        4,-        5,-        6,-        7,-        8,-        9,-        0,-        1-      ]-    },-    {-      "name": "basic, multiple selectors, multiple wildcards",-      "selector": "$[*,*]",-      "document": [-        0,-        1,-        2-      ],-      "result": [-        0,-        1,-        2,-        0,-        1,-        2-      ]-    },-    {-      "name": "basic, empty segment",-      "selector": "$[]",-      "invalid_selector": true-    },-    {-      "name": "basic, descendant segment, index",-      "selector": "$..[1]",-      "document": {-        "o": [-          0,-          1,-          [-            2,-            3-          ]-        ]-      },-      "result": [-        1,-        3-      ]-    },-    {-      "name": "basic, descendant segment, name shorthand",-      "selector": "$..a",-      "document": {-        "o": [-          {-            "a": "b"-          },-          {-            "a": "c"-          }-        ]-      },-      "result": [-        "b",-        "c"-      ]-    },-    {-      "name": "basic, descendant segment, wildcard shorthand, array data",-      "selector": "$..*",-      "document": [-        0,-        1-      ],-      "result": [-        0,-        1-      ]-    },-    {-      "name": "basic, descendant segment, wildcard selector, array data",-      "selector": "$..[*]",-      "document": [-        0,-        1-      ],-      "result": [-        0,-        1-      ]-    },-    {-      "name": "basic, descendant segment, wildcard selector, nested arrays",-      "selector": "$..[*]",-      "document": [-        [-          [-            1-          ]-        ],-        [-          2-        ]-      ],-      "results": [-        [-          [-            [-              1-            ]-          ],-          [-            2-          ],-          [-            1-          ],-          1,-          2-        ],-        [-          [-            [-              1-            ]-          ],-          [-            2-          ],-          [-            1-          ],-          2,-          1-        ]-      ]-    },-    {-      "name": "basic, descendant segment, wildcard selector, nested objects",-      "selector": "$..[*]",-      "document": {-        "a": {-          "c": {-            "e": 1-          }-        },-        "b": {-          "d": 2-        }-      },-      "results": [-        [-          {-            "c": {-              "e": 1-            }-          },-          {-            "d": 2-          },-          {-            "e": 1-          },-          1,-          2-        ],-        [-          {-            "c": {-              "e": 1-            }-          },-          {-            "d": 2-          },-          {-            "e": 1-          },-          2,-          1-        ],-        [-          {-            "c": {-              "e": 1-            }-          },-          {-            "d": 2-          },-          2,-          {-            "e": 1-          },-          1-        ],-        [-          {-            "d": 2-          },-          {-            "c": {-              "e": 1-            }-          },-          {-            "e": 1-          },-          1,-          2-        ],-        [-          {-            "d": 2-          },-          {-            "c": {-              "e": 1-            }-          },-          {-            "e": 1-          },-          2,-          1-        ],-        [-          {-            "d": 2-          },-          {-            "c": {-              "e": 1-            }-          },-          2,-          {-            "e": 1-          },-          1-        ]-      ]-    },-    {-      "name": "basic, descendant segment, wildcard shorthand, object data",-      "selector": "$..*",-      "document": {-        "a": "b"-      },-      "result": [-        "b"-      ]-    },-    {-      "name": "basic, descendant segment, wildcard shorthand, nested data",-      "selector": "$..*",-      "document": {-        "o": [-          {-            "a": "b"-          }-        ]-      },-      "result": [-        [-          {-            "a": "b"-          }-        ],-        {-          "a": "b"-        },-        "b"-      ]-    },-    {-      "name": "basic, descendant segment, multiple selectors",-      "selector": "$..['a','d']",-      "document": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        }-      ],-      "result": [-        "b",-        "e",-        "c",-        "f"-      ]-    },-    {-      "name": "basic, descendant segment, object traversal, multiple selectors",-      "selector": "$..['a','d']",-      "document": {-        "x": {-          "a": "b",-          "d": "e"-        },-        "y": {-          "a": "c",-          "d": "f"-        }-      },-      "results": [-        [-          "b",-          "e",-          "c",-          "f"-        ],-        [-          "c",-          "f",-          "b",-          "e"-        ]-      ]-    },-    {-      "name": "basic, bald descendant segment",-      "selector": "$..",-      "invalid_selector": true-    },-    {-      "name": "filter, existence, without segments",-      "selector": "$[?@]",-      "document": {-        "a": 1,-        "b": null-      },-      "results": [-        [-          1,-          null-        ],-        [-          null,-          1-        ]-      ]-    },-    {-      "name": "filter, existence",-      "selector": "$[?@.a]",-      "document": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "b": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "b",-          "d": "e"-        }-      ]-    },-    {-      "name": "filter, existence, present with null",-      "selector": "$[?@.a]",-      "document": [-        {-          "a": null,-          "d": "e"-        },-        {-          "b": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": null,-          "d": "e"-        }-      ]-    },-    {-      "name": "filter, absolute existence, without segments",-      "selector": "$[?$]",-      "document": {-        "a": 1,-        "b": null-      },-      "results": [-        [-          1,-          null-        ],-        [-          null,-          1-        ]-      ]-    },-    {-      "name": "filter, absolute existence, with segments",-      "selector": "$[?$.*.a]",-      "document": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "b": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "b": "c",-          "d": "f"-        }-      ]-    },-    {-      "name": "filter, equals string, single quotes",-      "selector": "$[?@.a=='b']",-      "document": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "b",-          "d": "e"-        }-      ]-    },-    {-      "name": "filter, equals numeric string, single quotes",-      "selector": "$[?@.a=='1']",-      "document": [-        {-          "a": "1",-          "d": "e"-        },-        {-          "a": 1,-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "1",-          "d": "e"-        }-      ]-    },-    {-      "name": "filter, equals string, double quotes",-      "selector": "$[?@.a==\"b\"]",-      "document": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "b",-          "d": "e"-        }-      ]-    },-    {-      "name": "filter, equals numeric string, double quotes",-      "selector": "$[?@.a==\"1\"]",-      "document": [-        {-          "a": "1",-          "d": "e"-        },-        {-          "a": 1,-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "1",-          "d": "e"-        }-      ]-    },-    {-      "name": "filter, equals number",-      "selector": "$[?@.a==1]",-      "document": [-        {-          "a": 1,-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        },-        {-          "a": 2,-          "d": "f"-        },-        {-          "a": "1",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": 1,-          "d": "e"-        }-      ]-    },-    {-      "name": "filter, equals null",-      "selector": "$[?@.a==null]",-      "document": [-        {-          "a": null,-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": null,-          "d": "e"-        }-      ]-    },-    {-      "name": "filter, equals null, absent from data",-      "selector": "$[?@.a==null]",-      "document": [-        {-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        }-      ],-      "result": []-    },-    {-      "name": "filter, equals true",-      "selector": "$[?@.a==true]",-      "document": [-        {-          "a": true,-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": true,-          "d": "e"-        }-      ]-    },-    {-      "name": "filter, equals false",-      "selector": "$[?@.a==false]",-      "document": [-        {-          "a": false,-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": false,-          "d": "e"-        }-      ]-    },-    {-      "name": "filter, equals self",-      "selector": "$[?@==@]",-      "document": [-        1,-        null,-        true,-        {-          "a": "b"-        },-        [-          false-        ]-      ],-      "result": [-        1,-        null,-        true,-        {-          "a": "b"-        },-        [-          false-        ]-      ]-    },-    {-      "name": "filter, absolute, equals self",-      "selector": "$[?$==$]",-      "document": [-        1,-        null,-        true,-        {-          "a": "b"-        },-        [-          false-        ]-      ],-      "result": [-        1,-        null,-        true,-        {-          "a": "b"-        },-        [-          false-        ]-      ]-    },-    {-      "name": "filter, deep equality, arrays",-      "selector": "$[?@.a==@.b]",-      "document": [-        {-          "a": false,-          "b": [-            1,-            2-          ]-        },-        {-          "a": [-            [-              1,-              [-                2-              ]-            ]-          ],-          "b": [-            [-              1,-              [-                2-              ]-            ]-          ]-        },-        {-          "a": [-            [-              1,-              [-                2-              ]-            ]-          ],-          "b": [-            [-              [-                2-              ],-              1-            ]-          ]-        },-        {-          "a": [-            [-              1,-              [-                2-              ]-            ]-          ],-          "b": [-            [-              1,-              2-            ]-          ]-        }-      ],-      "result": [-        {-          "a": [-            [-              1,-              [-                2-              ]-            ]-          ],-          "b": [-            [-              1,-              [-                2-              ]-            ]-          ]-        }-      ]-    },-    {-      "name": "filter, deep equality, objects",-      "selector": "$[?@.a==@.b]",-      "document": [-        {-          "a": false,-          "b": {-            "x": 1,-            "y": {-              "z": 1-            }-          }-        },-        {-          "a": {-            "x": 1,-            "y": {-              "z": 1-            }-          },-          "b": {-            "x": 1,-            "y": {-              "z": 1-            }-          }-        },-        {-          "a": {-            "x": 1,-            "y": {-              "z": 1-            }-          },-          "b": {-            "y": {-              "z": 1-            },-            "x": 1-          }-        },-        {-          "a": {-            "x": 1,-            "y": {-              "z": 1-            }-          },-          "b": {-            "x": 1-          }-        },-        {-          "a": {-            "x": 1,-            "y": {-              "z": 1-            }-          },-          "b": {-            "x": 1,-            "y": {-              "z": 2-            }-          }-        }-      ],-      "result": [-        {-          "a": {-            "x": 1,-            "y": {-              "z": 1-            }-          },-          "b": {-            "x": 1,-            "y": {-              "z": 1-            }-          }-        },-        {-          "a": {-            "x": 1,-            "y": {-              "z": 1-            }-          },-          "b": {-            "y": {-              "z": 1-            },-            "x": 1-          }-        }-      ]-    },-    {-      "name": "filter, not-equals string, single quotes",-      "selector": "$[?@.a!='b']",-      "document": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "c",-          "d": "f"-        }-      ]-    },-    {-      "name": "filter, not-equals numeric string, single quotes",-      "selector": "$[?@.a!='1']",-      "document": [-        {-          "a": "1",-          "d": "e"-        },-        {-          "a": 1,-          "d": "f"-        }-      ],-      "result": [-        {-          "a": 1,-          "d": "f"-        }-      ]-    },-    {-      "name": "filter, not-equals string, single quotes, different type",-      "selector": "$[?@.a!='b']",-      "document": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "a": 1,-          "d": "f"-        }-      ],-      "result": [-        {-          "a": 1,-          "d": "f"-        }-      ]-    },-    {-      "name": "filter, not-equals string, double quotes",-      "selector": "$[?@.a!=\"b\"]",-      "document": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "c",-          "d": "f"-        }-      ]-    },-    {-      "name": "filter, not-equals numeric string, double quotes",-      "selector": "$[?@.a!=\"1\"]",-      "document": [-        {-          "a": "1",-          "d": "e"-        },-        {-          "a": 1,-          "d": "f"-        }-      ],-      "result": [-        {-          "a": 1,-          "d": "f"-        }-      ]-    },-    {-      "name": "filter, not-equals string, double quotes, different types",-      "selector": "$[?@.a!=\"b\"]",-      "document": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "a": 1,-          "d": "f"-        }-      ],-      "result": [-        {-          "a": 1,-          "d": "f"-        }-      ]-    },-    {-      "name": "filter, not-equals number",-      "selector": "$[?@.a!=1]",-      "document": [-        {-          "a": 1,-          "d": "e"-        },-        {-          "a": 2,-          "d": "f"-        },-        {-          "a": "1",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": 2,-          "d": "f"-        },-        {-          "a": "1",-          "d": "f"-        }-      ]-    },-    {-      "name": "filter, not-equals number, different types",-      "selector": "$[?@.a!=1]",-      "document": [-        {-          "a": 1,-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "c",-          "d": "f"-        }-      ]-    },-    {-      "name": "filter, not-equals null",-      "selector": "$[?@.a!=null]",-      "document": [-        {-          "a": null,-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "c",-          "d": "f"-        }-      ]-    },-    {-      "name": "filter, not-equals null, absent from data",-      "selector": "$[?@.a!=null]",-      "document": [-        {-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        }-      ]-    },-    {-      "name": "filter, not-equals true",-      "selector": "$[?@.a!=true]",-      "document": [-        {-          "a": true,-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "c",-          "d": "f"-        }-      ]-    },-    {-      "name": "filter, not-equals false",-      "selector": "$[?@.a!=false]",-      "document": [-        {-          "a": false,-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "c",-          "d": "f"-        }-      ]-    },-    {-      "name": "filter, less than string, single quotes",-      "selector": "$[?@.a<'c']",-      "document": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "b",-          "d": "e"-        }-      ]-    },-    {-      "name": "filter, less than string, double quotes",-      "selector": "$[?@.a<\"c\"]",-      "document": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "b",-          "d": "e"-        }-      ]-    },-    {-      "name": "filter, less than number",-      "selector": "$[?@.a<10]",-      "document": [-        {-          "a": 1,-          "d": "e"-        },-        {-          "a": 10,-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        },-        {-          "a": 20,-          "d": "f"-        }-      ],-      "result": [-        {-          "a": 1,-          "d": "e"-        }-      ]-    },-    {-      "name": "filter, less than null",-      "selector": "$[?@.a<null]",-      "document": [-        {-          "a": null,-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        }-      ],-      "result": []-    },-    {-      "name": "filter, less than true",-      "selector": "$[?@.a<true]",-      "document": [-        {-          "a": true,-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        }-      ],-      "result": []-    },-    {-      "name": "filter, less than false",-      "selector": "$[?@.a<false]",-      "document": [-        {-          "a": false,-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        }-      ],-      "result": []-    },-    {-      "name": "filter, less than or equal to string, single quotes",-      "selector": "$[?@.a<='c']",-      "document": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        }-      ]-    },-    {-      "name": "filter, less than or equal to string, double quotes",-      "selector": "$[?@.a<=\"c\"]",-      "document": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        }-      ]-    },-    {-      "name": "filter, less than or equal to number",-      "selector": "$[?@.a<=10]",-      "document": [-        {-          "a": 1,-          "d": "e"-        },-        {-          "a": 10,-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        },-        {-          "a": 20,-          "d": "f"-        }-      ],-      "result": [-        {-          "a": 1,-          "d": "e"-        },-        {-          "a": 10,-          "d": "e"-        }-      ]-    },-    {-      "name": "filter, less than or equal to null",-      "selector": "$[?@.a<=null]",-      "document": [-        {-          "a": null,-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": null,-          "d": "e"-        }-      ]-    },-    {-      "name": "filter, less than or equal to true",-      "selector": "$[?@.a<=true]",-      "document": [-        {-          "a": true,-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": true,-          "d": "e"-        }-      ]-    },-    {-      "name": "filter, less than or equal to false",-      "selector": "$[?@.a<=false]",-      "document": [-        {-          "a": false,-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": false,-          "d": "e"-        }-      ]-    },-    {-      "name": "filter, greater than string, single quotes",-      "selector": "$[?@.a>'c']",-      "document": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        },-        {-          "a": "d",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "d",-          "d": "f"-        }-      ]-    },-    {-      "name": "filter, greater than string, double quotes",-      "selector": "$[?@.a>\"c\"]",-      "document": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        },-        {-          "a": "d",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "d",-          "d": "f"-        }-      ]-    },-    {-      "name": "filter, greater than number",-      "selector": "$[?@.a>10]",-      "document": [-        {-          "a": 1,-          "d": "e"-        },-        {-          "a": 10,-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        },-        {-          "a": 20,-          "d": "f"-        }-      ],-      "result": [-        {-          "a": 20,-          "d": "f"-        }-      ]-    },-    {-      "name": "filter, greater than null",-      "selector": "$[?@.a>null]",-      "document": [-        {-          "a": null,-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        }-      ],-      "result": []-    },-    {-      "name": "filter, greater than true",-      "selector": "$[?@.a>true]",-      "document": [-        {-          "a": true,-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        }-      ],-      "result": []-    },-    {-      "name": "filter, greater than false",-      "selector": "$[?@.a>false]",-      "document": [-        {-          "a": false,-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        }-      ],-      "result": []-    },-    {-      "name": "filter, greater than or equal to string, single quotes",-      "selector": "$[?@.a>='c']",-      "document": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        },-        {-          "a": "d",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "c",-          "d": "f"-        },-        {-          "a": "d",-          "d": "f"-        }-      ]-    },-    {-      "name": "filter, greater than or equal to string, double quotes",-      "selector": "$[?@.a>=\"c\"]",-      "document": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        },-        {-          "a": "d",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "c",-          "d": "f"-        },-        {-          "a": "d",-          "d": "f"-        }-      ]-    },-    {-      "name": "filter, greater than or equal to number",-      "selector": "$[?@.a>=10]",-      "document": [-        {-          "a": 1,-          "d": "e"-        },-        {-          "a": 10,-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        },-        {-          "a": 20,-          "d": "f"-        }-      ],-      "result": [-        {-          "a": 10,-          "d": "e"-        },-        {-          "a": 20,-          "d": "f"-        }-      ]-    },-    {-      "name": "filter, greater than or equal to null",-      "selector": "$[?@.a>=null]",-      "document": [-        {-          "a": null,-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": null,-          "d": "e"-        }-      ]-    },-    {-      "name": "filter, greater than or equal to true",-      "selector": "$[?@.a>=true]",-      "document": [-        {-          "a": true,-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": true,-          "d": "e"-        }-      ]-    },-    {-      "name": "filter, greater than or equal to false",-      "selector": "$[?@.a>=false]",-      "document": [-        {-          "a": false,-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": false,-          "d": "e"-        }-      ]-    },-    {-      "name": "filter, exists and not-equals null, absent from data",-      "selector": "$[?@.a&&@.a!=null]",-      "document": [-        {-          "d": "e"-        },-        {-          "a": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "c",-          "d": "f"-        }-      ]-    },-    {-      "name": "filter, exists and exists, data false",-      "selector": "$[?@.a&&@.b]",-      "document": [-        {-          "a": false,-          "b": false-        },-        {-          "b": false-        },-        {-          "c": false-        }-      ],-      "result": [-        {-          "a": false,-          "b": false-        }-      ]-    },-    {-      "name": "filter, exists or exists, data false",-      "selector": "$[?@.a||@.b]",-      "document": [-        {-          "a": false,-          "b": false-        },-        {-          "b": false-        },-        {-          "c": false-        }-      ],-      "result": [-        {-          "a": false,-          "b": false-        },-        {-          "b": false-        }-      ]-    },-    {-      "name": "filter, and",-      "selector": "$[?@.a>0&&@.a<10]",-      "document": [-        {-          "a": -10,-          "d": "e"-        },-        {-          "a": 5,-          "d": "f"-        },-        {-          "a": 20,-          "d": "f"-        }-      ],-      "result": [-        {-          "a": 5,-          "d": "f"-        }-      ]-    },-    {-      "name": "filter, or",-      "selector": "$[?@.a=='b'||@.a=='d']",-      "document": [-        {-          "a": "a",-          "d": "e"-        },-        {-          "a": "b",-          "d": "f"-        },-        {-          "a": "c",-          "d": "f"-        },-        {-          "a": "d",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "b",-          "d": "f"-        },-        {-          "a": "d",-          "d": "f"-        }-      ]-    },-    {-      "name": "filter, not expression",-      "selector": "$[?!(@.a=='b')]",-      "document": [-        {-          "a": "a",-          "d": "e"-        },-        {-          "a": "b",-          "d": "f"-        },-        {-          "a": "d",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "a",-          "d": "e"-        },-        {-          "a": "d",-          "d": "f"-        }-      ]-    },-    {-      "name": "filter, not exists",-      "selector": "$[?!@.a]",-      "document": [-        {-          "a": "a",-          "d": "e"-        },-        {-          "d": "f"-        },-        {-          "a": "d",-          "d": "f"-        }-      ],-      "result": [-        {-          "d": "f"-        }-      ]-    },-    {-      "name": "filter, not exists, data null",-      "selector": "$[?!@.a]",-      "document": [-        {-          "a": null,-          "d": "e"-        },-        {-          "d": "f"-        },-        {-          "a": "d",-          "d": "f"-        }-      ],-      "result": [-        {-          "d": "f"-        }-      ]-    },-    {-      "name": "filter, non-singular existence, wildcard",-      "selector": "$[?@.*]",-      "document": [-        1,-        [],-        [-          2-        ],-        {},-        {-          "a": 3-        }-      ],-      "result": [-        [-          2-        ],-        {-          "a": 3-        }-      ]-    },-    {-      "name": "filter, non-singular existence, multiple",-      "selector": "$[?@[0, 0, 'a']]",-      "document": [-        1,-        [],-        [-          2-        ],-        [-          2,-          3-        ],-        {-          "a": 3-        },-        {-          "b": 4-        },-        {-          "a": 3,-          "b": 4-        }-      ],-      "result": [-        [-          2-        ],-        [-          2,-          3-        ],-        {-          "a": 3-        },-        {-          "a": 3,-          "b": 4-        }-      ]-    },-    {-      "name": "filter, non-singular existence, slice",-      "selector": "$[?@[0:2]]",-      "document": [-        1,-        [],-        [-          2-        ],-        [-          2,-          3,-          4-        ],-        {},-        {-          "a": 3-        }-      ],-      "result": [-        [-          2-        ],-        [-          2,-          3,-          4-        ]-      ]-    },-    {-      "name": "filter, non-singular existence, negated",-      "selector": "$[?!@.*]",-      "document": [-        1,-        [],-        [-          2-        ],-        {},-        {-          "a": 3-        }-      ],-      "result": [-        1,-        [],-        {}-      ]-    },-    {-      "name": "filter, non-singular query in comparison, slice",-      "selector": "$[?@[0:0]==0]",-      "invalid_selector": true-    },-    {-      "name": "filter, non-singular query in comparison, all children",-      "selector": "$[?@[*]==0]",-      "invalid_selector": true-    },-    {-      "name": "filter, non-singular query in comparison, descendants",-      "selector": "$[?@..a==0]",-      "invalid_selector": true-    },-    {-      "name": "filter, non-singular query in comparison, combined",-      "selector": "$[?@.a[*].a==0]",-      "invalid_selector": true-    },-    {-      "name": "filter, nested",-      "selector": "$[?@[?@>1]]",-      "document": [-        [-          0-        ],-        [-          0,-          1-        ],-        [-          0,-          1,-          2-        ],-        [-          42-        ]-      ],-      "result": [-        [-          0,-          1,-          2-        ],-        [-          42-        ]-      ]-    },-    {-      "name": "filter, name segment on primitive, selects nothing",-      "selector": "$[?@.a == 1]",-      "document": {-        "a": 1-      },-      "result": []-    },-    {-      "name": "filter, name segment on array, selects nothing",-      "selector": "$[?@['0'] == 5]",-      "document": [-        [-          5,-          6-        ]-      ],-      "result": []-    },-    {-      "name": "filter, index segment on object, selects nothing",-      "selector": "$[?@[0] == 5]",-      "document": [-        {-          "0": 5-        }-      ],-      "result": []-    },-    {-      "name": "filter, relative non-singular query, index, equal",-      "selector": "$[?(@[0, 0]==42)]",-      "invalid_selector": true,-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "filter, relative non-singular query, index, not equal",-      "selector": "$[?(@[0, 0]!=42)]",-      "invalid_selector": true,-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "filter, relative non-singular query, index, less-or-equal",-      "selector": "$[?(@[0, 0]<=42)]",-      "invalid_selector": true,-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "filter, relative non-singular query, name, equal",-      "selector": "$[?(@['a', 'a']==42)]",-      "invalid_selector": true,-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "filter, relative non-singular query, name, not equal",-      "selector": "$[?(@['a', 'a']!=42)]",-      "invalid_selector": true,-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "filter, relative non-singular query, name, less-or-equal",-      "selector": "$[?(@['a', 'a']<=42)]",-      "invalid_selector": true,-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "filter, relative non-singular query, combined, equal",-      "selector": "$[?(@[0, '0']==42)]",-      "invalid_selector": true,-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "filter, relative non-singular query, combined, not equal",-      "selector": "$[?(@[0, '0']!=42)]",-      "invalid_selector": true,-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "filter, relative non-singular query, combined, less-or-equal",-      "selector": "$[?(@[0, '0']<=42)]",-      "invalid_selector": true,-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "filter, relative non-singular query, wildcard, equal",-      "selector": "$[?(@.*==42)]",-      "invalid_selector": true-    },-    {-      "name": "filter, relative non-singular query, wildcard, not equal",-      "selector": "$[?(@.*!=42)]",-      "invalid_selector": true-    },-    {-      "name": "filter, relative non-singular query, wildcard, less-or-equal",-      "selector": "$[?(@.*<=42)]",-      "invalid_selector": true-    },-    {-      "name": "filter, relative non-singular query, slice, equal",-      "selector": "$[?(@[0:0]==42)]",-      "invalid_selector": true-    },-    {-      "name": "filter, relative non-singular query, slice, not equal",-      "selector": "$[?(@[0:0]!=42)]",-      "invalid_selector": true-    },-    {-      "name": "filter, relative non-singular query, slice, less-or-equal",-      "selector": "$[?(@[0:0]<=42)]",-      "invalid_selector": true-    },-    {-      "name": "filter, absolute non-singular query, index, equal",-      "selector": "$[?($[0, 0]==42)]",-      "invalid_selector": true,-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "filter, absolute non-singular query, index, not equal",-      "selector": "$[?($[0, 0]!=42)]",-      "invalid_selector": true,-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "filter, absolute non-singular query, index, less-or-equal",-      "selector": "$[?($[0, 0]<=42)]",-      "invalid_selector": true,-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "filter, absolute non-singular query, name, equal",-      "selector": "$[?($['a', 'a']==42)]",-      "invalid_selector": true,-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "filter, absolute non-singular query, name, not equal",-      "selector": "$[?($['a', 'a']!=42)]",-      "invalid_selector": true,-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "filter, absolute non-singular query, name, less-or-equal",-      "selector": "$[?($['a', 'a']<=42)]",-      "invalid_selector": true,-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "filter, absolute non-singular query, combined, equal",-      "selector": "$[?($[0, '0']==42)]",-      "invalid_selector": true,-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "filter, absolute non-singular query, combined, not equal",-      "selector": "$[?($[0, '0']!=42)]",-      "invalid_selector": true,-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "filter, absolute non-singular query, combined, less-or-equal",-      "selector": "$[?($[0, '0']<=42)]",-      "invalid_selector": true,-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "filter, absolute non-singular query, wildcard, equal",-      "selector": "$[?($.*==42)]",-      "invalid_selector": true-    },-    {-      "name": "filter, absolute non-singular query, wildcard, not equal",-      "selector": "$[?($.*!=42)]",-      "invalid_selector": true-    },-    {-      "name": "filter, absolute non-singular query, wildcard, less-or-equal",-      "selector": "$[?($.*<=42)]",-      "invalid_selector": true-    },-    {-      "name": "filter, absolute non-singular query, slice, equal",-      "selector": "$[?($[0:0]==42)]",-      "invalid_selector": true-    },-    {-      "name": "filter, absolute non-singular query, slice, not equal",-      "selector": "$[?($[0:0]!=42)]",-      "invalid_selector": true-    },-    {-      "name": "filter, absolute non-singular query, slice, less-or-equal",-      "selector": "$[?($[0:0]<=42)]",-      "invalid_selector": true-    },-    {-      "name": "filter, multiple selectors",-      "selector": "$[?@.a,?@.b]",-      "document": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "b": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "b": "c",-          "d": "f"-        }-      ]-    },-    {-      "name": "filter, multiple selectors, comparison",-      "selector": "$[?@.a=='b',?@.b=='x']",-      "document": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "b": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "b",-          "d": "e"-        }-      ]-    },-    {-      "name": "filter, multiple selectors, overlapping",-      "selector": "$[?@.a,?@.d]",-      "document": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "b": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "a": "b",-          "d": "e"-        },-        {-          "b": "c",-          "d": "f"-        }-      ]-    },-    {-      "name": "filter, multiple selectors, filter and index",-      "selector": "$[?@.a,1]",-      "document": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "b": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "b": "c",-          "d": "f"-        }-      ]-    },-    {-      "name": "filter, multiple selectors, filter and wildcard",-      "selector": "$[?@.a,*]",-      "document": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "b": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "a": "b",-          "d": "e"-        },-        {-          "b": "c",-          "d": "f"-        }-      ]-    },-    {-      "name": "filter, multiple selectors, filter and slice",-      "selector": "$[?@.a,1:]",-      "document": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "b": "c",-          "d": "f"-        },-        {-          "g": "h"-        }-      ],-      "result": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "b": "c",-          "d": "f"-        },-        {-          "g": "h"-        }-      ]-    },-    {-      "name": "filter, multiple selectors, comparison filter, index and slice",-      "selector": "$[1, ?@.a=='b', 1:]",-      "document": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "b": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "b": "c",-          "d": "f"-        },-        {-          "a": "b",-          "d": "e"-        },-        {-          "b": "c",-          "d": "f"-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "filter, equals number, zero and negative zero",-      "selector": "$[?@.a==0]",-      "document": [-        {-          "a": 0,-          "d": "e"-        },-        {-          "a": 0.1,-          "d": "f"-        },-        {-          "a": "0",-          "d": "g"-        }-      ],-      "result": [-        {-          "a": 0,-          "d": "e"-        }-      ]-    },-    {-      "name": "filter, equals number, negative zero and zero",-      "selector": "$[?@.a==-0]",-      "document": [-        {-          "a": 0,-          "d": "e"-        },-        {-          "a": 0.1,-          "d": "f"-        },-        {-          "a": "0",-          "d": "g"-        }-      ],-      "result": [-        {-          "a": 0,-          "d": "e"-        }-      ]-    },-    {-      "name": "filter, equals number, with and without decimal fraction",-      "selector": "$[?@.a==1.0]",-      "document": [-        {-          "a": 1,-          "d": "e"-        },-        {-          "a": 2,-          "d": "f"-        },-        {-          "a": "1",-          "d": "g"-        }-      ],-      "result": [-        {-          "a": 1,-          "d": "e"-        }-      ]-    },-    {-      "name": "filter, equals number, exponent",-      "selector": "$[?@.a==1e2]",-      "document": [-        {-          "a": 100,-          "d": "e"-        },-        {-          "a": 100.1,-          "d": "f"-        },-        {-          "a": "100",-          "d": "g"-        }-      ],-      "result": [-        {-          "a": 100,-          "d": "e"-        }-      ]-    },-    {-      "name": "filter, equals number, exponent upper e",-      "selector": "$[?@.a==1E2]",-      "document": [-        {-          "a": 100,-          "d": "e"-        },-        {-          "a": 100.1,-          "d": "f"-        },-        {-          "a": "100",-          "d": "g"-        }-      ],-      "result": [-        {-          "a": 100,-          "d": "e"-        }-      ]-    },-    {-      "name": "filter, equals number, positive exponent",-      "selector": "$[?@.a==1e+2]",-      "document": [-        {-          "a": 100,-          "d": "e"-        },-        {-          "a": 100.1,-          "d": "f"-        },-        {-          "a": "100",-          "d": "g"-        }-      ],-      "result": [-        {-          "a": 100,-          "d": "e"-        }-      ]-    },-    {-      "name": "filter, equals number, negative exponent",-      "selector": "$[?@.a==1e-2]",-      "document": [-        {-          "a": 0.01,-          "d": "e"-        },-        {-          "a": 0.02,-          "d": "f"-        },-        {-          "a": "0.01",-          "d": "g"-        }-      ],-      "result": [-        {-          "a": 0.01,-          "d": "e"-        }-      ]-    },-    {-      "name": "filter, equals number, exponent 0",-      "selector": "$[?@.a==1e0]",-      "document": [-        {-          "a": 1,-          "d": "e"-        },-        {-          "a": 2,-          "d": "f"-        },-        {-          "a": "1",-          "d": "g"-        }-      ],-      "result": [-        {-          "a": 1,-          "d": "e"-        }-      ]-    },-    {-      "name": "filter, equals number, exponent -0",-      "selector": "$[?@.a==1e-0]",-      "document": [-        {-          "a": 1,-          "d": "e"-        },-        {-          "a": 2,-          "d": "f"-        },-        {-          "a": "1",-          "d": "g"-        }-      ],-      "result": [-        {-          "a": 1,-          "d": "e"-        }-      ]-    },-    {-      "name": "filter, equals number, exponent +0",-      "selector": "$[?@.a==1e+0]",-      "document": [-        {-          "a": 1,-          "d": "e"-        },-        {-          "a": 2,-          "d": "f"-        },-        {-          "a": "1",-          "d": "g"-        }-      ],-      "result": [-        {-          "a": 1,-          "d": "e"-        }-      ]-    },-    {-      "name": "filter, equals number, exponent leading -0",-      "selector": "$[?@.a==1e-02]",-      "document": [-        {-          "a": 0.01,-          "d": "e"-        },-        {-          "a": 0.02,-          "d": "f"-        },-        {-          "a": "0.01",-          "d": "g"-        }-      ],-      "result": [-        {-          "a": 0.01,-          "d": "e"-        }-      ]-    },-    {-      "name": "filter, equals number, exponent +00",-      "selector": "$[?@.a==1e+00]",-      "document": [-        {-          "a": 1,-          "d": "e"-        },-        {-          "a": 2,-          "d": "f"-        },-        {-          "a": "1",-          "d": "g"-        }-      ],-      "result": [-        {-          "a": 1,-          "d": "e"-        }-      ]-    },-    {-      "name": "filter, equals number, decimal fraction",-      "selector": "$[?@.a==1.1]",-      "document": [-        {-          "a": 1.1,-          "d": "e"-        },-        {-          "a": 1,-          "d": "f"-        },-        {-          "a": "1.1",-          "d": "g"-        }-      ],-      "result": [-        {-          "a": 1.1,-          "d": "e"-        }-      ]-    },-    {-      "name": "filter, equals number, decimal fraction, trailing 0",-      "selector": "$[?@.a==1.10]",-      "document": [-        {-          "a": 1.1,-          "d": "e"-        },-        {-          "a": 1,-          "d": "f"-        },-        {-          "a": "1.1",-          "d": "g"-        }-      ],-      "result": [-        {-          "a": 1.1,-          "d": "e"-        }-      ]-    },-    {-      "name": "filter, equals number, decimal fraction, exponent",-      "selector": "$[?@.a==1.1e2]",-      "document": [-        {-          "a": 110,-          "d": "e"-        },-        {-          "a": 110.1,-          "d": "f"-        },-        {-          "a": "110",-          "d": "g"-        }-      ],-      "result": [-        {-          "a": 110,-          "d": "e"-        }-      ]-    },-    {-      "name": "filter, equals number, decimal fraction, positive exponent",-      "selector": "$[?@.a==1.1e+2]",-      "document": [-        {-          "a": 110,-          "d": "e"-        },-        {-          "a": 110.1,-          "d": "f"-        },-        {-          "a": "110",-          "d": "g"-        }-      ],-      "result": [-        {-          "a": 110,-          "d": "e"-        }-      ]-    },-    {-      "name": "filter, equals number, decimal fraction, negative exponent",-      "selector": "$[?@.a==1.1e-2]",-      "document": [-        {-          "a": 0.011,-          "d": "e"-        },-        {-          "a": 0.012,-          "d": "f"-        },-        {-          "a": "0.011",-          "d": "g"-        }-      ],-      "result": [-        {-          "a": 0.011,-          "d": "e"-        }-      ]-    },-    {-      "name": "filter, equals number, invalid plus",-      "selector": "$[?@.a==+1]",-      "invalid_selector": true-    },-    {-      "name": "filter, equals number, invalid minus space",-      "selector": "$[?@.a==- 1]",-      "invalid_selector": true-    },-    {-      "name": "filter, equals number, invalid double minus",-      "selector": "$[?@.a==--1]",-      "invalid_selector": true-    },-    {-      "name": "filter, equals number, invalid no int digit",-      "selector": "$[?@.a==.1]",-      "invalid_selector": true-    },-    {-      "name": "filter, equals number, invalid minus no int digit",-      "selector": "$[?@.a==-.1]",-      "invalid_selector": true-    },-    {-      "name": "filter, equals number, invalid 00",-      "selector": "$[?@.a==00]",-      "invalid_selector": true-    },-    {-      "name": "filter, equals number, invalid leading 0",-      "selector": "$[?@.a==01]",-      "invalid_selector": true-    },-    {-      "name": "filter, equals number, invalid no fractional digit",-      "selector": "$[?@.a==1.]",-      "invalid_selector": true-    },-    {-      "name": "filter, equals number, invalid middle minus",-      "selector": "$[?@.a==1.-1]",-      "invalid_selector": true-    },-    {-      "name": "filter, equals number, invalid no fractional digit e",-      "selector": "$[?@.a==1.e1]",-      "invalid_selector": true-    },-    {-      "name": "filter, equals number, invalid no e digit",-      "selector": "$[?@.a==1e]",-      "invalid_selector": true-    },-    {-      "name": "filter, equals number, invalid no e digit minus",-      "selector": "$[?@.a==1e-]",-      "invalid_selector": true-    },-    {-      "name": "filter, equals number, invalid double e",-      "selector": "$[?@.a==1eE1]",-      "invalid_selector": true-    },-    {-      "name": "filter, equals number, invalid e digit double minus",-      "selector": "$[?@.a==1e--1]",-      "invalid_selector": true-    },-    {-      "name": "filter, equals number, invalid e digit plus minus",-      "selector": "$[?@.a==1e+-1]",-      "invalid_selector": true-    },-    {-      "name": "filter, equals number, invalid e decimal",-      "selector": "$[?@.a==1e2.3]",-      "invalid_selector": true-    },-    {-      "name": "filter, equals number, invalid multi e",-      "selector": "$[?@.a==1e2e3]",-      "invalid_selector": true-    },-    {-      "name": "filter, equals, special nothing",-      "selector": "$.values[?length(@.a) == value($..c)]",-      "document": {-        "c": "cd",-        "values": [-          {-            "a": "ab"-          },-          {-            "c": "d"-          },-          {-            "a": null-          }-        ]-      },-      "result": [-        {-          "c": "d"-        },-        {-          "a": null-        }-      ],-      "tags": [-        "function"-      ]-    },-    {-      "name": "filter, equals, empty node list and empty node list",-      "selector": "$[?@.a == @.b]",-      "document": [-        {-          "a": 1-        },-        {-          "b": 2-        },-        {-          "c": 3-        }-      ],-      "result": [-        {-          "c": 3-        }-      ]-    },-    {-      "name": "filter, equals, empty node list and special nothing",-      "selector": "$[?@.a == length(@.b)]",-      "document": [-        {-          "a": 1-        },-        {-          "b": 2-        },-        {-          "c": 3-        }-      ],-      "result": [-        {-          "b": 2-        },-        {-          "c": 3-        }-      ],-      "tags": [-        "function",-        "whitespace"-      ]-    },-    {-      "name": "filter, object data",-      "selector": "$[?@<3]",-      "document": {-        "a": 1,-        "b": 2,-        "c": 3-      },-      "results": [-        [-          1,-          2-        ],-        [-          2,-          1-        ]-      ]-    },-    {-      "name": "filter, and binds more tightly than or",-      "selector": "$[?@.a || @.b && @.c]",-      "document": [-        {-          "a": 1-        },-        {-          "b": 2,-          "c": 3-        },-        {-          "c": 3-        },-        {-          "b": 2-        },-        {-          "a": 1,-          "b": 2,-          "c": 3-        }-      ],-      "result": [-        {-          "a": 1-        },-        {-          "b": 2,-          "c": 3-        },-        {-          "a": 1,-          "b": 2,-          "c": 3-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "filter, left to right evaluation",-      "selector": "$[?@.a && @.b || @.c]",-      "document": [-        {-          "a": 1-        },-        {-          "b": 2-        },-        {-          "a": 1,-          "b": 2-        },-        {-          "a": 1,-          "c": 3-        },-        {-          "b": 1,-          "c": 3-        },-        {-          "c": 3-        },-        {-          "a": 1,-          "b": 2,-          "c": 3-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 2-        },-        {-          "a": 1,-          "c": 3-        },-        {-          "b": 1,-          "c": 3-        },-        {-          "c": 3-        },-        {-          "a": 1,-          "b": 2,-          "c": 3-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "filter, group terms, left",-      "selector": "$[?(@.a || @.b) && @.c]",-      "document": [-        {-          "a": 1,-          "b": 2-        },-        {-          "a": 1,-          "c": 3-        },-        {-          "b": 2,-          "c": 3-        },-        {-          "a": 1-        },-        {-          "b": 2-        },-        {-          "c": 3-        },-        {-          "a": 1,-          "b": 2,-          "c": 3-        }-      ],-      "result": [-        {-          "a": 1,-          "c": 3-        },-        {-          "b": 2,-          "c": 3-        },-        {-          "a": 1,-          "b": 2,-          "c": 3-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "filter, group terms, right",-      "selector": "$[?@.a && (@.b || @.c)]",-      "document": [-        {-          "a": 1-        },-        {-          "a": 1,-          "b": 2-        },-        {-          "a": 1,-          "c": 2-        },-        {-          "b": 2-        },-        {-          "c": 2-        },-        {-          "a": 1,-          "b": 2,-          "c": 3-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 2-        },-        {-          "a": 1,-          "c": 2-        },-        {-          "a": 1,-          "b": 2,-          "c": 3-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "filter, string literal, single quote in double quotes",-      "selector": "$[?@ == \"quoted' literal\"]",-      "document": [-        "quoted' literal",-        "a",-        "quoted\\' literal"-      ],-      "result": [-        "quoted' literal"-      ]-    },-    {-      "name": "filter, string literal, double quote in single quotes",-      "selector": "$[?@ == 'quoted\" literal']",-      "document": [-        "quoted\" literal",-        "a",-        "quoted\\\" literal",-        "'quoted\" literal'"-      ],-      "result": [-        "quoted\" literal"-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "filter, string literal, escaped single quote in single quotes",-      "selector": "$[?@ == 'quoted\\' literal']",-      "document": [-        "quoted' literal",-        "a",-        "quoted\\' literal",-        "'quoted\" literal'"-      ],-      "result": [-        "quoted' literal"-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "filter, string literal, escaped double quote in double quotes",-      "selector": "$[?@ == \"quoted\\\" literal\"]",-      "document": [-        "quoted\" literal",-        "a",-        "quoted\\\" literal",-        "'quoted\" literal'"-      ],-      "result": [-        "quoted\" literal"-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "filter, literal true must be compared",-      "selector": "$[?true]",-      "invalid_selector": true-    },-    {-      "name": "filter, literal false must be compared",-      "selector": "$[?false]",-      "invalid_selector": true-    },-    {-      "name": "filter, literal string must be compared",-      "selector": "$[?'abc']",-      "invalid_selector": true-    },-    {-      "name": "filter, literal int must be compared",-      "selector": "$[?2]",-      "invalid_selector": true-    },-    {-      "name": "filter, literal float must be compared",-      "selector": "$[?2.2]",-      "invalid_selector": true-    },-    {-      "name": "filter, literal null must be compared",-      "selector": "$[?null]",-      "invalid_selector": true-    },-    {-      "name": "filter, and, literals must be compared",-      "selector": "$[?true && false]",-      "invalid_selector": true,-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "filter, or, literals must be compared",-      "selector": "$[?true || false]",-      "invalid_selector": true,-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "filter, and, right hand literal must be compared",-      "selector": "$[?true == false && false]",-      "invalid_selector": true,-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "filter, or, right hand literal must be compared",-      "selector": "$[?true == false || false]",-      "invalid_selector": true,-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "filter, and, left hand literal must be compared",-      "selector": "$[?false && true == false]",-      "invalid_selector": true,-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "filter, or, left hand literal must be compared",-      "selector": "$[?false || true == false]",-      "invalid_selector": true,-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "filter, true, incorrectly capitalized",-      "selector": "$[?@==True]",-      "invalid_selector": true,-      "tags": [-        "case"-      ]-    },-    {-      "name": "filter, false, incorrectly capitalized",-      "selector": "$[?@==False]",-      "invalid_selector": true,-      "tags": [-        "case"-      ]-    },-    {-      "name": "filter, null, incorrectly capitalized",-      "selector": "$[?@==Null]",-      "invalid_selector": true,-      "tags": [-        "case"-      ]-    },-    {-      "name": "index selector, first element",-      "selector": "$[0]",-      "document": [-        "first",-        "second"-      ],-      "result": [-        "first"-      ],-      "tags": [-        "index"-      ]-    },-    {-      "name": "index selector, second element",-      "selector": "$[1]",-      "document": [-        "first",-        "second"-      ],-      "result": [-        "second"-      ],-      "tags": [-        "index"-      ]-    },-    {-      "name": "index selector, out of bound",-      "selector": "$[2]",-      "document": [-        "first",-        "second"-      ],-      "result": [],-      "tags": [-        "boundary",-        "index"-      ]-    },-    {-      "name": "index selector, min exact index",-      "selector": "$[-9007199254740991]",-      "document": [-        "first",-        "second"-      ],-      "result": [],-      "tags": [-        "boundary",-        "index"-      ]-    },-    {-      "name": "index selector, max exact index",-      "selector": "$[9007199254740991]",-      "document": [-        "first",-        "second"-      ],-      "result": [],-      "tags": [-        "boundary",-        "index"-      ]-    },-    {-      "name": "index selector, min exact index - 1",-      "selector": "$[-9007199254740992]",-      "invalid_selector": true,-      "tags": [-        "boundary",-        "index"-      ]-    },-    {-      "name": "index selector, max exact index + 1",-      "selector": "$[9007199254740992]",-      "invalid_selector": true,-      "tags": [-        "boundary",-        "index"-      ]-    },-    {-      "name": "index selector, overflowing index",-      "selector": "$[231584178474632390847141970017375815706539969331281128078915168015826259279872]",-      "invalid_selector": true,-      "tags": [-        "boundary",-        "index"-      ]-    },-    {-      "name": "index selector, not actually an index, overflowing index leads into general text",-      "selector": "$[231584178474632390847141970017375815706539969331281128078915168SomeRandomText]",-      "invalid_selector": true,-      "tags": [-        "index"-      ]-    },-    {-      "name": "index selector, negative",-      "selector": "$[-1]",-      "document": [-        "first",-        "second"-      ],-      "result": [-        "second"-      ],-      "tags": [-        "index"-      ]-    },-    {-      "name": "index selector, more negative",-      "selector": "$[-2]",-      "document": [-        "first",-        "second"-      ],-      "result": [-        "first"-      ],-      "tags": [-        "index"-      ]-    },-    {-      "name": "index selector, negative out of bound",-      "selector": "$[-3]",-      "document": [-        "first",-        "second"-      ],-      "result": [],-      "tags": [-        "boundary",-        "index"-      ]-    },-    {-      "name": "index selector, on object",-      "selector": "$[0]",-      "document": {-        "foo": 1-      },-      "result": [],-      "tags": [-        "index"-      ]-    },-    {-      "name": "index selector, leading 0",-      "selector": "$[01]",-      "invalid_selector": true,-      "tags": [-        "index"-      ]-    },-    {-      "name": "index selector, decimal",-      "selector": "$[1.0]",-      "invalid_selector": true,-      "tags": [-        "index"-      ]-    },-    {-      "name": "index selector, plus",-      "selector": "$[+1]",-      "invalid_selector": true,-      "tags": [-        "index"-      ]-    },-    {-      "name": "index selector, minus space",-      "selector": "$[- 1]",-      "invalid_selector": true,-      "tags": [-        "index",-        "whitespace"-      ]-    },-    {-      "name": "index selector, -0",-      "selector": "$[-0]",-      "invalid_selector": true,-      "tags": [-        "index"-      ]-    },-    {-      "name": "index selector, leading -0",-      "selector": "$[-01]",-      "invalid_selector": true,-      "tags": [-        "index"-      ]-    },-    {-      "name": "name selector, double quotes",-      "selector": "$[\"a\"]",-      "document": {-        "a": "A",-        "b": "B"-      },-      "result": [-        "A"-      ]-    },-    {-      "name": "name selector, double quotes, absent data",-      "selector": "$[\"c\"]",-      "document": {-        "a": "A",-        "b": "B"-      },-      "result": []-    },-    {-      "name": "name selector, double quotes, array data",-      "selector": "$[\"a\"]",-      "document": [-        "first",-        "second"-      ],-      "result": []-    },-    {-      "name": "name selector, double quotes, embedded U+0000",-      "selector": "$[\"\u0000\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, embedded U+0001",-      "selector": "$[\"\u0001\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, embedded U+0002",-      "selector": "$[\"\u0002\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, embedded U+0003",-      "selector": "$[\"\u0003\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, embedded U+0004",-      "selector": "$[\"\u0004\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, embedded U+0005",-      "selector": "$[\"\u0005\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, embedded U+0006",-      "selector": "$[\"\u0006\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, embedded U+0007",-      "selector": "$[\"\u0007\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, embedded U+0008",-      "selector": "$[\"\b\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, embedded U+0009",-      "selector": "$[\"\t\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, embedded U+000A",-      "selector": "$[\"\n\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, embedded U+000B",-      "selector": "$[\"\u000b\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, embedded U+000C",-      "selector": "$[\"\f\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, embedded U+000D",-      "selector": "$[\"\r\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, embedded U+000E",-      "selector": "$[\"\u000e\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, embedded U+000F",-      "selector": "$[\"\u000f\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, embedded U+0010",-      "selector": "$[\"\u0010\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, embedded U+0011",-      "selector": "$[\"\u0011\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, embedded U+0012",-      "selector": "$[\"\u0012\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, embedded U+0013",-      "selector": "$[\"\u0013\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, embedded U+0014",-      "selector": "$[\"\u0014\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, embedded U+0015",-      "selector": "$[\"\u0015\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, embedded U+0016",-      "selector": "$[\"\u0016\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, embedded U+0017",-      "selector": "$[\"\u0017\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, embedded U+0018",-      "selector": "$[\"\u0018\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, embedded U+0019",-      "selector": "$[\"\u0019\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, embedded U+001A",-      "selector": "$[\"\u001a\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, embedded U+001B",-      "selector": "$[\"\u001b\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, embedded U+001C",-      "selector": "$[\"\u001c\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, embedded U+001D",-      "selector": "$[\"\u001d\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, embedded U+001E",-      "selector": "$[\"\u001e\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, embedded U+001F",-      "selector": "$[\"\u001f\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, embedded U+0020",-      "selector": "$[\" \"]",-      "document": {-        " ": "A"-      },-      "result": [-        "A"-      ],-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, embedded U+007F",-      "selector": "$[\"\"]",-      "document": {-        "": "A"-      },-      "result": [-        "A"-      ],-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, supplementary plane character",-      "selector": "$[\"𝄞\"]",-      "document": {-        "𝄞": "A"-      },-      "result": [-        "A"-      ],-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, escaped double quote",-      "selector": "$[\"\\\"\"]",-      "document": {-        "\"": "A"-      },-      "result": [-        "A"-      ]-    },-    {-      "name": "name selector, double quotes, escaped reverse solidus",-      "selector": "$[\"\\\\\"]",-      "document": {-        "\\": "A"-      },-      "result": [-        "A"-      ]-    },-    {-      "name": "name selector, double quotes, escaped solidus",-      "selector": "$[\"\\/\"]",-      "document": {-        "/": "A"-      },-      "result": [-        "A"-      ]-    },-    {-      "name": "name selector, double quotes, escaped backspace",-      "selector": "$[\"\\b\"]",-      "document": {-        "\b": "A"-      },-      "result": [-        "A"-      ]-    },-    {-      "name": "name selector, double quotes, escaped form feed",-      "selector": "$[\"\\f\"]",-      "document": {-        "\f": "A"-      },-      "result": [-        "A"-      ]-    },-    {-      "name": "name selector, double quotes, escaped line feed",-      "selector": "$[\"\\n\"]",-      "document": {-        "\n": "A"-      },-      "result": [-        "A"-      ]-    },-    {-      "name": "name selector, double quotes, escaped carriage return",-      "selector": "$[\"\\r\"]",-      "document": {-        "\r": "A"-      },-      "result": [-        "A"-      ]-    },-    {-      "name": "name selector, double quotes, escaped tab",-      "selector": "$[\"\\t\"]",-      "document": {-        "\t": "A"-      },-      "result": [-        "A"-      ]-    },-    {-      "name": "name selector, double quotes, escaped ☺, upper case hex",-      "selector": "$[\"\\u263A\"]",-      "document": {-        "☺": "A"-      },-      "result": [-        "A"-      ],-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, escaped ☺, lower case hex",-      "selector": "$[\"\\u263a\"]",-      "document": {-        "☺": "A"-      },-      "result": [-        "A"-      ],-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, surrogate pair 𝄞",-      "selector": "$[\"\\uD834\\uDD1E\"]",-      "document": {-        "𝄞": "A"-      },-      "result": [-        "A"-      ],-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, surrogate pair 😀",-      "selector": "$[\"\\uD83D\\uDE00\"]",-      "document": {-        "😀": "A"-      },-      "result": [-        "A"-      ],-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, before high surrogates",-      "selector": "$[\"\\uD7FF\\uD7FF\"]",-      "document": {-        "퟿퟿": "A"-      },-      "result": [-        "A"-      ],-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, after low surrogates",-      "selector": "$[\"\\uE000\\uE000\"]",-      "document": {-        "": "A"-      },-      "result": [-        "A"-      ],-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, invalid escaped single quote",-      "selector": "$[\"\\'\"]",-      "invalid_selector": true-    },-    {-      "name": "name selector, double quotes, embedded double quote",-      "selector": "$[\"\"\"]",-      "invalid_selector": true-    },-    {-      "name": "name selector, double quotes, incomplete escape",-      "selector": "$[\"\\\"]",-      "invalid_selector": true-    },-    {-      "name": "name selector, double quotes, escape at end of line",-      "selector": "$[\"\\\n\"]",-      "invalid_selector": true-    },-    {-      "name": "name selector, double quotes, question mark escape",-      "selector": "$[\"\\?\"]",-      "invalid_selector": true-    },-    {-      "name": "name selector, double quotes, bell escape",-      "selector": "$[\"\\a\"]",-      "invalid_selector": true-    },-    {-      "name": "name selector, double quotes, vertical tab escape",-      "selector": "$[\"\\v\"]",-      "invalid_selector": true-    },-    {-      "name": "name selector, double quotes, 0 escape",-      "selector": "$[\"\\0\"]",-      "invalid_selector": true-    },-    {-      "name": "name selector, double quotes, x escape",-      "selector": "$[\"\\x12\"]",-      "invalid_selector": true-    },-    {-      "name": "name selector, double quotes, n escape",-      "selector": "$[\"\\N{LATIN CAPITAL LETTER A}\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, unicode escape no hex",-      "selector": "$[\"\\u\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, unicode escape too few hex",-      "selector": "$[\"\\u123\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, unicode escape upper u",-      "selector": "$[\"\\U1234\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, unicode escape upper u long",-      "selector": "$[\"\\U0010FFFF\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, unicode escape plus",-      "selector": "$[\"\\u+1234\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, unicode escape brackets",-      "selector": "$[\"\\u{1234}\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, unicode escape brackets long",-      "selector": "$[\"\\u{10ffff}\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, single high surrogate",-      "selector": "$[\"\\uD800\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, single low surrogate",-      "selector": "$[\"\\uDC00\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, high high surrogate",-      "selector": "$[\"\\uD800\\uD800\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, low low surrogate",-      "selector": "$[\"\\uDC00\\uDC00\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, surrogate non-surrogate",-      "selector": "$[\"\\uD800\\u1234\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, non-surrogate surrogate",-      "selector": "$[\"\\u1234\\uDC00\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, surrogate supplementary",-      "selector": "$[\"\\uD800𝄞\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, supplementary surrogate",-      "selector": "$[\"𝄞\\uDC00\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, double quotes, surrogate incomplete low",-      "selector": "$[\"\\uD800\\uDC0\"]",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, single quotes",-      "selector": "$['a']",-      "document": {-        "a": "A",-        "b": "B"-      },-      "result": [-        "A"-      ]-    },-    {-      "name": "name selector, single quotes, absent data",-      "selector": "$['c']",-      "document": {-        "a": "A",-        "b": "B"-      },-      "result": []-    },-    {-      "name": "name selector, single quotes, array data",-      "selector": "$['a']",-      "document": [-        "first",-        "second"-      ],-      "result": []-    },-    {-      "name": "name selector, single quotes, embedded U+0000",-      "selector": "$['\u0000']",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, single quotes, embedded U+0001",-      "selector": "$['\u0001']",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, single quotes, embedded U+0002",-      "selector": "$['\u0002']",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, single quotes, embedded U+0003",-      "selector": "$['\u0003']",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, single quotes, embedded U+0004",-      "selector": "$['\u0004']",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, single quotes, embedded U+0005",-      "selector": "$['\u0005']",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, single quotes, embedded U+0006",-      "selector": "$['\u0006']",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, single quotes, embedded U+0007",-      "selector": "$['\u0007']",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, single quotes, embedded U+0008",-      "selector": "$['\b']",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, single quotes, embedded U+0009",-      "selector": "$['\t']",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, single quotes, embedded U+000A",-      "selector": "$['\n']",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, single quotes, embedded U+000B",-      "selector": "$['\u000b']",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, single quotes, embedded U+000C",-      "selector": "$['\f']",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, single quotes, embedded U+000D",-      "selector": "$['\r']",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, single quotes, embedded U+000E",-      "selector": "$['\u000e']",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, single quotes, embedded U+000F",-      "selector": "$['\u000f']",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, single quotes, embedded U+0010",-      "selector": "$['\u0010']",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, single quotes, embedded U+0011",-      "selector": "$['\u0011']",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, single quotes, embedded U+0012",-      "selector": "$['\u0012']",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, single quotes, embedded U+0013",-      "selector": "$['\u0013']",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, single quotes, embedded U+0014",-      "selector": "$['\u0014']",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, single quotes, embedded U+0015",-      "selector": "$['\u0015']",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, single quotes, embedded U+0016",-      "selector": "$['\u0016']",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, single quotes, embedded U+0017",-      "selector": "$['\u0017']",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, single quotes, embedded U+0018",-      "selector": "$['\u0018']",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, single quotes, embedded U+0019",-      "selector": "$['\u0019']",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, single quotes, embedded U+001A",-      "selector": "$['\u001a']",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, single quotes, embedded U+001B",-      "selector": "$['\u001b']",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, single quotes, embedded U+001C",-      "selector": "$['\u001c']",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, single quotes, embedded U+001D",-      "selector": "$['\u001d']",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, single quotes, embedded U+001E",-      "selector": "$['\u001e']",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, single quotes, embedded U+001F",-      "selector": "$['\u001f']",-      "invalid_selector": true,-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, single quotes, embedded U+0020",-      "selector": "$[' ']",-      "document": {-        " ": "A"-      },-      "result": [-        "A"-      ],-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, single quotes, escaped single quote",-      "selector": "$['\\'']",-      "document": {-        "'": "A"-      },-      "result": [-        "A"-      ]-    },-    {-      "name": "name selector, single quotes, escaped reverse solidus",-      "selector": "$['\\\\']",-      "document": {-        "\\": "A"-      },-      "result": [-        "A"-      ]-    },-    {-      "name": "name selector, single quotes, escaped solidus",-      "selector": "$['\\/']",-      "document": {-        "/": "A"-      },-      "result": [-        "A"-      ],-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, single quotes, escaped backspace",-      "selector": "$['\\b']",-      "document": {-        "\b": "A"-      },-      "result": [-        "A"-      ]-    },-    {-      "name": "name selector, single quotes, escaped form feed",-      "selector": "$['\\f']",-      "document": {-        "\f": "A"-      },-      "result": [-        "A"-      ]-    },-    {-      "name": "name selector, single quotes, escaped line feed",-      "selector": "$['\\n']",-      "document": {-        "\n": "A"-      },-      "result": [-        "A"-      ]-    },-    {-      "name": "name selector, single quotes, escaped carriage return",-      "selector": "$['\\r']",-      "document": {-        "\r": "A"-      },-      "result": [-        "A"-      ]-    },-    {-      "name": "name selector, single quotes, escaped tab",-      "selector": "$['\\t']",-      "document": {-        "\t": "A"-      },-      "result": [-        "A"-      ]-    },-    {-      "name": "name selector, single quotes, escaped ☺, upper case hex",-      "selector": "$['\\u263A']",-      "document": {-        "☺": "A"-      },-      "result": [-        "A"-      ],-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, single quotes, escaped ☺, lower case hex",-      "selector": "$['\\u263a']",-      "document": {-        "☺": "A"-      },-      "result": [-        "A"-      ],-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, single quotes, surrogate pair 𝄞",-      "selector": "$['\\uD834\\uDD1E']",-      "document": {-        "𝄞": "A"-      },-      "result": [-        "A"-      ],-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, single quotes, surrogate pair 😀",-      "selector": "$['\\uD83D\\uDE00']",-      "document": {-        "😀": "A"-      },-      "result": [-        "A"-      ],-      "tags": [-        "unicode"-      ]-    },-    {-      "name": "name selector, single quotes, invalid escaped double quote",-      "selector": "$['\\\"']",-      "invalid_selector": true-    },-    {-      "name": "name selector, single quotes, embedded single quote",-      "selector": "$[''']",-      "invalid_selector": true-    },-    {-      "name": "name selector, single quotes, incomplete escape",-      "selector": "$['\\']",-      "invalid_selector": true-    },-    {-      "name": "name selector, double quotes, empty",-      "selector": "$[\"\"]",-      "document": {-        "a": "A",-        "b": "B",-        "": "C"-      },-      "result": [-        "C"-      ]-    },-    {-      "name": "name selector, single quotes, empty",-      "selector": "$['']",-      "document": {-        "a": "A",-        "b": "B",-        "": "C"-      },-      "result": [-        "C"-      ]-    },-    {-      "name": "slice selector, slice selector",-      "selector": "$[1:3]",-      "document": [-        0,-        1,-        2,-        3,-        4,-        5,-        6,-        7,-        8,-        9-      ],-      "result": [-        1,-        2-      ],-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, slice selector with step",-      "selector": "$[1:6:2]",-      "document": [-        0,-        1,-        2,-        3,-        4,-        5,-        6,-        7,-        8,-        9-      ],-      "result": [-        1,-        3,-        5-      ],-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, slice selector with everything omitted, short form",-      "selector": "$[:]",-      "document": [-        0,-        1,-        2,-        3-      ],-      "result": [-        0,-        1,-        2,-        3-      ],-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, slice selector with everything omitted, long form",-      "selector": "$[::]",-      "document": [-        0,-        1,-        2,-        3-      ],-      "result": [-        0,-        1,-        2,-        3-      ],-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, slice selector with start omitted",-      "selector": "$[:2]",-      "document": [-        0,-        1,-        2,-        3,-        4,-        5,-        6,-        7,-        8,-        9-      ],-      "result": [-        0,-        1-      ],-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, slice selector with start and end omitted",-      "selector": "$[::2]",-      "document": [-        0,-        1,-        2,-        3,-        4,-        5,-        6,-        7,-        8,-        9-      ],-      "result": [-        0,-        2,-        4,-        6,-        8-      ],-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, negative step with default start and end",-      "selector": "$[::-1]",-      "document": [-        0,-        1,-        2,-        3-      ],-      "result": [-        3,-        2,-        1,-        0-      ],-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, negative step with default start",-      "selector": "$[:0:-1]",-      "document": [-        0,-        1,-        2,-        3-      ],-      "result": [-        3,-        2,-        1-      ],-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, negative step with default end",-      "selector": "$[2::-1]",-      "document": [-        0,-        1,-        2,-        3-      ],-      "result": [-        2,-        1,-        0-      ],-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, larger negative step",-      "selector": "$[::-2]",-      "document": [-        0,-        1,-        2,-        3-      ],-      "result": [-        3,-        1-      ],-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, negative range with default step",-      "selector": "$[-1:-3]",-      "document": [-        0,-        1,-        2,-        3,-        4,-        5,-        6,-        7,-        8,-        9-      ],-      "result": [],-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, negative range with negative step",-      "selector": "$[-1:-3:-1]",-      "document": [-        0,-        1,-        2,-        3,-        4,-        5,-        6,-        7,-        8,-        9-      ],-      "result": [-        9,-        8-      ],-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, negative range with larger negative step",-      "selector": "$[-1:-6:-2]",-      "document": [-        0,-        1,-        2,-        3,-        4,-        5,-        6,-        7,-        8,-        9-      ],-      "result": [-        9,-        7,-        5-      ],-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, larger negative range with larger negative step",-      "selector": "$[-1:-7:-2]",-      "document": [-        0,-        1,-        2,-        3,-        4,-        5,-        6,-        7,-        8,-        9-      ],-      "result": [-        9,-        7,-        5-      ],-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, negative from, positive to",-      "selector": "$[-5:7]",-      "document": [-        0,-        1,-        2,-        3,-        4,-        5,-        6,-        7,-        8,-        9-      ],-      "result": [-        5,-        6-      ],-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, negative from",-      "selector": "$[-2:]",-      "document": [-        0,-        1,-        2,-        3,-        4,-        5,-        6,-        7,-        8,-        9-      ],-      "result": [-        8,-        9-      ],-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, positive from, negative to",-      "selector": "$[1:-1]",-      "document": [-        0,-        1,-        2,-        3,-        4,-        5,-        6,-        7,-        8,-        9-      ],-      "result": [-        1,-        2,-        3,-        4,-        5,-        6,-        7,-        8-      ],-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, negative from, positive to, negative step",-      "selector": "$[-1:1:-1]",-      "document": [-        0,-        1,-        2,-        3,-        4,-        5,-        6,-        7,-        8,-        9-      ],-      "result": [-        9,-        8,-        7,-        6,-        5,-        4,-        3,-        2-      ],-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, positive from, negative to, negative step",-      "selector": "$[7:-5:-1]",-      "document": [-        0,-        1,-        2,-        3,-        4,-        5,-        6,-        7,-        8,-        9-      ],-      "result": [-        7,-        6-      ],-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, too many colons",-      "selector": "$[1:2:3:4]",-      "invalid_selector": true,-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, non-integer array index",-      "selector": "$[1:2:a]",-      "invalid_selector": true,-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, zero step",-      "selector": "$[1:2:0]",-      "document": [-        0,-        1,-        2,-        3,-        4,-        5,-        6,-        7,-        8,-        9-      ],-      "result": [],-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, empty range",-      "selector": "$[2:2]",-      "document": [-        0,-        1,-        2,-        3,-        4,-        5,-        6,-        7,-        8,-        9-      ],-      "result": [],-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, slice selector with everything omitted with empty array",-      "selector": "$[:]",-      "document": [],-      "result": [],-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, negative step with empty array",-      "selector": "$[::-1]",-      "document": [],-      "result": [],-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, maximal range with positive step",-      "selector": "$[0:10]",-      "document": [-        0,-        1,-        2,-        3,-        4,-        5,-        6,-        7,-        8,-        9-      ],-      "result": [-        0,-        1,-        2,-        3,-        4,-        5,-        6,-        7,-        8,-        9-      ],-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, maximal range with negative step",-      "selector": "$[9:0:-1]",-      "document": [-        0,-        1,-        2,-        3,-        4,-        5,-        6,-        7,-        8,-        9-      ],-      "result": [-        9,-        8,-        7,-        6,-        5,-        4,-        3,-        2,-        1-      ],-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, excessively large to value",-      "selector": "$[2:113667776004]",-      "document": [-        0,-        1,-        2,-        3,-        4,-        5,-        6,-        7,-        8,-        9-      ],-      "result": [-        2,-        3,-        4,-        5,-        6,-        7,-        8,-        9-      ],-      "tags": [-        "boundary",-        "slice"-      ]-    },-    {-      "name": "slice selector, excessively small from value",-      "selector": "$[-113667776004:1]",-      "document": [-        0,-        1,-        2,-        3,-        4,-        5,-        6,-        7,-        8,-        9-      ],-      "result": [-        0-      ],-      "tags": [-        "boundary",-        "slice"-      ]-    },-    {-      "name": "slice selector, excessively large from value with negative step",-      "selector": "$[113667776004:0:-1]",-      "document": [-        0,-        1,-        2,-        3,-        4,-        5,-        6,-        7,-        8,-        9-      ],-      "result": [-        9,-        8,-        7,-        6,-        5,-        4,-        3,-        2,-        1-      ],-      "tags": [-        "boundary",-        "slice"-      ]-    },-    {-      "name": "slice selector, excessively small to value with negative step",-      "selector": "$[3:-113667776004:-1]",-      "document": [-        0,-        1,-        2,-        3,-        4,-        5,-        6,-        7,-        8,-        9-      ],-      "result": [-        3,-        2,-        1,-        0-      ],-      "tags": [-        "boundary",-        "slice"-      ]-    },-    {-      "name": "slice selector, excessively large step",-      "selector": "$[1:10:113667776004]",-      "document": [-        0,-        1,-        2,-        3,-        4,-        5,-        6,-        7,-        8,-        9-      ],-      "result": [-        1-      ],-      "tags": [-        "boundary",-        "slice"-      ]-    },-    {-      "name": "slice selector, excessively small step",-      "selector": "$[-1:-10:-113667776004]",-      "document": [-        0,-        1,-        2,-        3,-        4,-        5,-        6,-        7,-        8,-        9-      ],-      "result": [-        9-      ],-      "tags": [-        "boundary",-        "slice"-      ]-    },-    {-      "name": "slice selector, start, min exact",-      "selector": "$[-9007199254740991::]",-      "document": [],-      "result": [],-      "tags": [-        "boundary",-        "slice"-      ]-    },-    {-      "name": "slice selector, start, max exact",-      "selector": "$[9007199254740991::]",-      "document": [],-      "result": [],-      "tags": [-        "boundary",-        "slice"-      ]-    },-    {-      "name": "slice selector, start, min exact - 1",-      "selector": "$[-9007199254740992::]",-      "invalid_selector": true,-      "tags": [-        "boundary",-        "slice"-      ]-    },-    {-      "name": "slice selector, start, max exact + 1",-      "selector": "$[9007199254740992::]",-      "invalid_selector": true,-      "tags": [-        "boundary",-        "slice"-      ]-    },-    {-      "name": "slice selector, end, min exact",-      "selector": "$[:-9007199254740991:]",-      "document": [],-      "result": [],-      "tags": [-        "boundary",-        "slice"-      ]-    },-    {-      "name": "slice selector, end, max exact",-      "selector": "$[:9007199254740991:]",-      "document": [],-      "result": [],-      "tags": [-        "boundary",-        "slice"-      ]-    },-    {-      "name": "slice selector, end, min exact - 1",-      "selector": "$[:-9007199254740992:]",-      "invalid_selector": true,-      "tags": [-        "boundary",-        "slice"-      ]-    },-    {-      "name": "slice selector, end, max exact + 1",-      "selector": "$[:9007199254740992:]",-      "invalid_selector": true,-      "tags": [-        "boundary",-        "slice"-      ]-    },-    {-      "name": "slice selector, step, min exact",-      "selector": "$[::-9007199254740991]",-      "document": [],-      "result": [],-      "tags": [-        "boundary",-        "slice"-      ]-    },-    {-      "name": "slice selector, step, max exact",-      "selector": "$[::9007199254740991]",-      "document": [],-      "result": [],-      "tags": [-        "boundary",-        "slice"-      ]-    },-    {-      "name": "slice selector, step, min exact - 1",-      "selector": "$[::-9007199254740992]",-      "invalid_selector": true,-      "tags": [-        "boundary",-        "slice"-      ]-    },-    {-      "name": "slice selector, step, max exact + 1",-      "selector": "$[::9007199254740992]",-      "invalid_selector": true,-      "tags": [-        "boundary",-        "slice"-      ]-    },-    {-      "name": "slice selector, overflowing to value",-      "selector": "$[2:231584178474632390847141970017375815706539969331281128078915168015826259279872]",-      "invalid_selector": true,-      "tags": [-        "boundary",-        "slice"-      ]-    },-    {-      "name": "slice selector, underflowing from value",-      "selector": "$[-231584178474632390847141970017375815706539969331281128078915168015826259279872:1]",-      "invalid_selector": true,-      "tags": [-        "boundary",-        "slice"-      ]-    },-    {-      "name": "slice selector, overflowing from value with negative step",-      "selector": "$[231584178474632390847141970017375815706539969331281128078915168015826259279872:0:-1]",-      "invalid_selector": true,-      "tags": [-        "boundary",-        "slice"-      ]-    },-    {-      "name": "slice selector, underflowing to value with negative step",-      "selector": "$[3:-231584178474632390847141970017375815706539969331281128078915168015826259279872:-1]",-      "invalid_selector": true,-      "tags": [-        "boundary",-        "slice"-      ]-    },-    {-      "name": "slice selector, overflowing step",-      "selector": "$[1:10:231584178474632390847141970017375815706539969331281128078915168015826259279872]",-      "invalid_selector": true,-      "tags": [-        "boundary",-        "slice"-      ]-    },-    {-      "name": "slice selector, underflowing step",-      "selector": "$[-1:-10:-231584178474632390847141970017375815706539969331281128078915168015826259279872]",-      "invalid_selector": true,-      "tags": [-        "boundary",-        "slice"-      ]-    },-    {-      "name": "slice selector, start, leading 0",-      "selector": "$[01::]",-      "invalid_selector": true,-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, start, decimal",-      "selector": "$[1.0::]",-      "invalid_selector": true,-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, start, plus",-      "selector": "$[+1::]",-      "invalid_selector": true,-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, start, minus space",-      "selector": "$[- 1::]",-      "invalid_selector": true,-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, start, -0",-      "selector": "$[-0::]",-      "invalid_selector": true,-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, start, leading -0",-      "selector": "$[-01::]",-      "invalid_selector": true,-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, end, leading 0",-      "selector": "$[:01:]",-      "invalid_selector": true,-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, end, decimal",-      "selector": "$[:1.0:]",-      "invalid_selector": true,-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, end, plus",-      "selector": "$[:+1:]",-      "invalid_selector": true,-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, end, minus space",-      "selector": "$[:- 1:]",-      "invalid_selector": true,-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, end, -0",-      "selector": "$[:-0:]",-      "invalid_selector": true,-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, end, leading -0",-      "selector": "$[:-01:]",-      "invalid_selector": true,-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, step, leading 0",-      "selector": "$[::01]",-      "invalid_selector": true,-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, step, decimal",-      "selector": "$[::1.0]",-      "invalid_selector": true,-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, step, plus",-      "selector": "$[::+1]",-      "invalid_selector": true,-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, step, minus space",-      "selector": "$[::- 1]",-      "invalid_selector": true,-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, step, -0",-      "selector": "$[::-0]",-      "invalid_selector": true,-      "tags": [-        "slice"-      ]-    },-    {-      "name": "slice selector, step, leading -0",-      "selector": "$[::-01]",-      "invalid_selector": true,-      "tags": [-        "slice"-      ]-    },-    {-      "name": "functions, count, count function",-      "selector": "$[?count(@..*)>2]",-      "document": [-        {-          "a": [-            1,-            2,-            3-          ]-        },-        {-          "a": [-            1-          ],-          "d": "f"-        },-        {-          "a": 1,-          "d": "f"-        }-      ],-      "result": [-        {-          "a": [-            1,-            2,-            3-          ]-        },-        {-          "a": [-            1-          ],-          "d": "f"-        }-      ],-      "tags": [-        "count",-        "function"-      ]-    },-    {-      "name": "functions, count, single-node arg",-      "selector": "$[?count(@.a)>1]",-      "document": [-        {-          "a": [-            1,-            2,-            3-          ]-        },-        {-          "a": [-            1-          ],-          "d": "f"-        },-        {-          "a": 1,-          "d": "f"-        }-      ],-      "result": [],-      "tags": [-        "count",-        "function"-      ]-    },-    {-      "name": "functions, count, multiple-selector arg",-      "selector": "$[?count(@['a','d'])>1]",-      "document": [-        {-          "a": [-            1,-            2,-            3-          ]-        },-        {-          "a": [-            1-          ],-          "d": "f"-        },-        {-          "a": 1,-          "d": "f"-        }-      ],-      "result": [-        {-          "a": [-            1-          ],-          "d": "f"-        },-        {-          "a": 1,-          "d": "f"-        }-      ],-      "tags": [-        "count",-        "function"-      ]-    },-    {-      "name": "functions, count, non-query arg, number",-      "selector": "$[?count(1)>2]",-      "invalid_selector": true,-      "tags": [-        "count",-        "function"-      ]-    },-    {-      "name": "functions, count, non-query arg, string",-      "selector": "$[?count('string')>2]",-      "invalid_selector": true,-      "tags": [-        "count",-        "function"-      ]-    },-    {-      "name": "functions, count, non-query arg, true",-      "selector": "$[?count(true)>2]",-      "invalid_selector": true,-      "tags": [-        "count",-        "function"-      ]-    },-    {-      "name": "functions, count, non-query arg, false",-      "selector": "$[?count(false)>2]",-      "invalid_selector": true,-      "tags": [-        "count",-        "function"-      ]-    },-    {-      "name": "functions, count, non-query arg, null",-      "selector": "$[?count(null)>2]",-      "invalid_selector": true,-      "tags": [-        "count",-        "function"-      ]-    },-    {-      "name": "functions, count, result must be compared",-      "selector": "$[?count(@..*)]",-      "invalid_selector": true,-      "tags": [-        "count",-        "function"-      ]-    },-    {-      "name": "functions, count, no params",-      "selector": "$[?count()==1]",-      "invalid_selector": true,-      "tags": [-        "count",-        "function"-      ]-    },-    {-      "name": "functions, count, too many params",-      "selector": "$[?count(@.a,@.b)==1]",-      "invalid_selector": true,-      "tags": [-        "count",-        "function"-      ]-    },-    {-      "name": "functions, length, string data",-      "selector": "$[?length(@.a)>=2]",-      "document": [-        {-          "a": "ab"-        },-        {-          "a": "d"-        }-      ],-      "result": [-        {-          "a": "ab"-        }-      ],-      "tags": [-        "function",-        "length"-      ]-    },-    {-      "name": "functions, length, string data, unicode",-      "selector": "$[?length(@)==2]",-      "document": [-        "☺",-        "☺☺",-        "☺☺☺",-        "ж",-        "жж",-        "жжж",-        "磨",-        "阿美",-        "形声字"-      ],-      "result": [-        "☺☺",-        "жж",-        "阿美"-      ],-      "tags": [-        "function",-        "length"-      ]-    },-    {-      "name": "functions, length, array data",-      "selector": "$[?length(@.a)>=2]",-      "document": [-        {-          "a": [-            1,-            2,-            3-          ]-        },-        {-          "a": [-            1-          ]-        }-      ],-      "result": [-        {-          "a": [-            1,-            2,-            3-          ]-        }-      ],-      "tags": [-        "function",-        "length"-      ]-    },-    {-      "name": "functions, length, missing data",-      "selector": "$[?length(@.a)>=2]",-      "document": [-        {-          "d": "f"-        }-      ],-      "result": [],-      "tags": [-        "function",-        "length"-      ]-    },-    {-      "name": "functions, length, number arg",-      "selector": "$[?length(1)>=2]",-      "document": [-        {-          "d": "f"-        }-      ],-      "result": [],-      "tags": [-        "function",-        "length"-      ]-    },-    {-      "name": "functions, length, true arg",-      "selector": "$[?length(true)>=2]",-      "document": [-        {-          "d": "f"-        }-      ],-      "result": [],-      "tags": [-        "function",-        "length"-      ]-    },-    {-      "name": "functions, length, false arg",-      "selector": "$[?length(false)>=2]",-      "document": [-        {-          "d": "f"-        }-      ],-      "result": [],-      "tags": [-        "function",-        "length"-      ]-    },-    {-      "name": "functions, length, null arg",-      "selector": "$[?length(null)>=2]",-      "document": [-        {-          "d": "f"-        }-      ],-      "result": [],-      "tags": [-        "function",-        "length"-      ]-    },-    {-      "name": "functions, length, result must be compared",-      "selector": "$[?length(@.a)]",-      "invalid_selector": true,-      "tags": [-        "function",-        "length"-      ]-    },-    {-      "name": "functions, length, no params",-      "selector": "$[?length()==1]",-      "invalid_selector": true,-      "tags": [-        "function",-        "length"-      ]-    },-    {-      "name": "functions, length, too many params",-      "selector": "$[?length(@.a,@.b)==1]",-      "invalid_selector": true,-      "tags": [-        "function",-        "length"-      ]-    },-    {-      "name": "functions, length, non-singular query arg",-      "selector": "$[?length(@.*)<3]",-      "invalid_selector": true,-      "tags": [-        "function",-        "length"-      ]-    },-    {-      "name": "functions, length, arg is a function expression",-      "selector": "$.values[?length(@.a)==length(value($..c))]",-      "document": {-        "c": "cd",-        "values": [-          {-            "a": "ab"-          },-          {-            "a": "d"-          }-        ]-      },-      "result": [-        {-          "a": "ab"-        }-      ],-      "tags": [-        "function",-        "length"-      ]-    },-    {-      "name": "functions, length, arg is special nothing",-      "selector": "$[?length(value(@.a))>0]",-      "document": [-        {-          "a": "ab"-        },-        {-          "c": "d"-        },-        {-          "a": null-        }-      ],-      "result": [-        {-          "a": "ab"-        }-      ],-      "tags": [-        "function",-        "length"-      ]-    },-    {-      "name": "functions, match, found match",-      "selector": "$[?match(@.a, 'a.*')]",-      "document": [-        {-          "a": "ab"-        }-      ],-      "result": [-        {-          "a": "ab"-        }-      ],-      "tags": [-        "function",-        "match"-      ]-    },-    {-      "name": "functions, match, double quotes",-      "selector": "$[?match(@.a, \"a.*\")]",-      "document": [-        {-          "a": "ab"-        }-      ],-      "result": [-        {-          "a": "ab"-        }-      ],-      "tags": [-        "function",-        "match"-      ]-    },-    {-      "name": "functions, match, regex from the document",-      "selector": "$.values[?match(@, $.regex)]",-      "document": {-        "regex": "b.?b",-        "values": [-          "abc",-          "bcd",-          "bab",-          "bba",-          "bbab",-          "b",-          true,-          [],-          {}-        ]-      },-      "result": [-        "bab"-      ],-      "tags": [-        "function",-        "match"-      ]-    },-    {-      "name": "functions, match, don't select match",-      "selector": "$[?!match(@.a, 'a.*')]",-      "document": [-        {-          "a": "ab"-        }-      ],-      "result": [],-      "tags": [-        "function",-        "match"-      ]-    },-    {-      "name": "functions, match, not a match",-      "selector": "$[?match(@.a, 'a.*')]",-      "document": [-        {-          "a": "bc"-        }-      ],-      "result": [],-      "tags": [-        "function",-        "match"-      ]-    },-    {-      "name": "functions, match, select non-match",-      "selector": "$[?!match(@.a, 'a.*')]",-      "document": [-        {-          "a": "bc"-        }-      ],-      "result": [-        {-          "a": "bc"-        }-      ],-      "tags": [-        "function",-        "match"-      ]-    },-    {-      "name": "functions, match, non-string first arg",-      "selector": "$[?match(1, 'a.*')]",-      "document": [-        {-          "a": "bc"-        }-      ],-      "result": [],-      "tags": [-        "function",-        "match"-      ]-    },-    {-      "name": "functions, match, non-string second arg",-      "selector": "$[?match(@.a, 1)]",-      "document": [-        {-          "a": "bc"-        }-      ],-      "result": [],-      "tags": [-        "function",-        "match"-      ]-    },-    {-      "name": "functions, match, filter, match function, unicode char class, uppercase",-      "selector": "$[?match(@, '\\\\p{Lu}')]",-      "document": [-        "ж",-        "Ж",-        "1",-        "жЖ",-        true,-        [],-        {}-      ],-      "result": [-        "Ж"-      ],-      "tags": [-        "function",-        "match"-      ]-    },-    {-      "name": "functions, match, filter, match function, unicode char class negated, uppercase",-      "selector": "$[?match(@, '\\\\P{Lu}')]",-      "document": [-        "ж",-        "Ж",-        "1",-        true,-        [],-        {}-      ],-      "result": [-        "ж",-        "1"-      ],-      "tags": [-        "function",-        "match"-      ]-    },-    {-      "name": "functions, match, filter, match function, unicode, surrogate pair",-      "selector": "$[?match(@, 'a.b')]",-      "document": [-        "a𐄁b",-        "ab",-        "1",-        true,-        [],-        {}-      ],-      "result": [-        "a𐄁b"-      ],-      "tags": [-        "function",-        "match"-      ]-    },-    {-      "name": "functions, match, dot matcher on \\u2028",-      "selector": "$[?match(@, '.')]",-      "document": [-        "
",-        "\r",-        "\n",-        true,-        [],-        {}-      ],-      "result": [-        "
"-      ],-      "tags": [-        "function",-        "match"-      ]-    },-    {-      "name": "functions, match, dot matcher on \\u2029",-      "selector": "$[?match(@, '.')]",-      "document": [-        "
",-        "\r",-        "\n",-        true,-        [],-        {}-      ],-      "result": [-        "
"-      ],-      "tags": [-        "function",-        "match"-      ]-    },-    {-      "name": "functions, match, result cannot be compared",-      "selector": "$[?match(@.a, 'a.*')==true]",-      "invalid_selector": true,-      "tags": [-        "function",-        "match"-      ]-    },-    {-      "name": "functions, match, too few params",-      "selector": "$[?match(@.a)==1]",-      "invalid_selector": true,-      "tags": [-        "function",-        "match"-      ]-    },-    {-      "name": "functions, match, too many params",-      "selector": "$[?match(@.a,@.b,@.c)==1]",-      "invalid_selector": true,-      "tags": [-        "function",-        "match"-      ]-    },-    {-      "name": "functions, match, arg is a function expression",-      "selector": "$.values[?match(@.a, value($..['regex']))]",-      "document": {-        "regex": "a.*",-        "values": [-          {-            "a": "ab"-          },-          {-            "a": "ba"-          }-        ]-      },-      "result": [-        {-          "a": "ab"-        }-      ],-      "tags": [-        "function",-        "match"-      ]-    },-    {-      "name": "functions, match, dot in character class",-      "selector": "$[?match(@, 'a[.b]c')]",-      "document": [-        "abc",-        "a.c",-        "axc"-      ],-      "result": [-        "abc",-        "a.c"-      ],-      "tags": [-        "function",-        "match"-      ]-    },-    {-      "name": "functions, match, escaped dot",-      "selector": "$[?match(@, 'a\\\\.c')]",-      "document": [-        "abc",-        "a.c",-        "axc"-      ],-      "result": [-        "a.c"-      ],-      "tags": [-        "function",-        "match"-      ]-    },-    {-      "name": "functions, match, escaped backslash before dot",-      "selector": "$[?match(@, 'a\\\\\\\\.c')]",-      "document": [-        "abc",-        "a.c",-        "axc",-        "a\\
c"-      ],-      "result": [-        "a\\
c"-      ],-      "tags": [-        "function",-        "match"-      ]-    },-    {-      "name": "functions, match, escaped left square bracket",-      "selector": "$[?match(@, 'a\\\\[.c')]",-      "document": [-        "abc",-        "a.c",-        "a[
c"-      ],-      "result": [-        "a[
c"-      ],-      "tags": [-        "function",-        "match"-      ]-    },-    {-      "name": "functions, match, escaped right square bracket",-      "selector": "$[?match(@, 'a[\\\\].]c')]",-      "document": [-        "abc",-        "a.c",-        "a
c",-        "a]c"-      ],-      "result": [-        "a.c",-        "a]c"-      ],-      "tags": [-        "function",-        "match"-      ]-    },-    {-      "name": "functions, match, explicit caret",-      "selector": "$[?match(@, '^ab.*')]",-      "document": [-        "abc",-        "axc",-        "ab",-        "xab"-      ],-      "result": [-        "abc",-        "ab"-      ],-      "tags": [-        "function",-        "match"-      ]-    },-    {-      "name": "functions, match, explicit dollar",-      "selector": "$[?match(@, '.*bc$')]",-      "document": [-        "abc",-        "axc",-        "ab",-        "abcx"-      ],-      "result": [-        "abc"-      ],-      "tags": [-        "function",-        "match"-      ]-    },-    {-      "name": "functions, search, at the end",-      "selector": "$[?search(@.a, 'a.*')]",-      "document": [-        {-          "a": "the end is ab"-        }-      ],-      "result": [-        {-          "a": "the end is ab"-        }-      ],-      "tags": [-        "function",-        "search"-      ]-    },-    {-      "name": "functions, search, double quotes",-      "selector": "$[?search(@.a, \"a.*\")]",-      "document": [-        {-          "a": "the end is ab"-        }-      ],-      "result": [-        {-          "a": "the end is ab"-        }-      ],-      "tags": [-        "function",-        "search"-      ]-    },-    {-      "name": "functions, search, at the start",-      "selector": "$[?search(@.a, 'a.*')]",-      "document": [-        {-          "a": "ab is at the start"-        }-      ],-      "result": [-        {-          "a": "ab is at the start"-        }-      ],-      "tags": [-        "function",-        "search"-      ]-    },-    {-      "name": "functions, search, in the middle",-      "selector": "$[?search(@.a, 'a.*')]",-      "document": [-        {-          "a": "contains two matches"-        }-      ],-      "result": [-        {-          "a": "contains two matches"-        }-      ],-      "tags": [-        "function",-        "search"-      ]-    },-    {-      "name": "functions, search, regex from the document",-      "selector": "$.values[?search(@, $.regex)]",-      "document": {-        "regex": "b.?b",-        "values": [-          "abc",-          "bcd",-          "bab",-          "bba",-          "bbab",-          "b",-          true,-          [],-          {}-        ]-      },-      "result": [-        "bab",-        "bba",-        "bbab"-      ],-      "tags": [-        "function",-        "search"-      ]-    },-    {-      "name": "functions, search, don't select match",-      "selector": "$[?!search(@.a, 'a.*')]",-      "document": [-        {-          "a": "contains two matches"-        }-      ],-      "result": [],-      "tags": [-        "function",-        "search"-      ]-    },-    {-      "name": "functions, search, not a match",-      "selector": "$[?search(@.a, 'a.*')]",-      "document": [-        {-          "a": "bc"-        }-      ],-      "result": [],-      "tags": [-        "function",-        "search"-      ]-    },-    {-      "name": "functions, search, select non-match",-      "selector": "$[?!search(@.a, 'a.*')]",-      "document": [-        {-          "a": "bc"-        }-      ],-      "result": [-        {-          "a": "bc"-        }-      ],-      "tags": [-        "function",-        "search"-      ]-    },-    {-      "name": "functions, search, non-string first arg",-      "selector": "$[?search(1, 'a.*')]",-      "document": [-        {-          "a": "bc"-        }-      ],-      "result": [],-      "tags": [-        "function",-        "search"-      ]-    },-    {-      "name": "functions, search, non-string second arg",-      "selector": "$[?search(@.a, 1)]",-      "document": [-        {-          "a": "bc"-        }-      ],-      "result": [],-      "tags": [-        "function",-        "search"-      ]-    },-    {-      "name": "functions, search, filter, search function, unicode char class, uppercase",-      "selector": "$[?search(@, '\\\\p{Lu}')]",-      "document": [-        "ж",-        "Ж",-        "1",-        "жЖ",-        true,-        [],-        {}-      ],-      "result": [-        "Ж",-        "жЖ"-      ],-      "tags": [-        "function",-        "search"-      ]-    },-    {-      "name": "functions, search, filter, search function, unicode char class negated, uppercase",-      "selector": "$[?search(@, '\\\\P{Lu}')]",-      "document": [-        "ж",-        "Ж",-        "1",-        true,-        [],-        {}-      ],-      "result": [-        "ж",-        "1"-      ],-      "tags": [-        "function",-        "search"-      ]-    },-    {-      "name": "functions, search, filter, search function, unicode, surrogate pair",-      "selector": "$[?search(@, 'a.b')]",-      "document": [-        "a𐄁bc",-        "abc",-        "1",-        true,-        [],-        {}-      ],-      "result": [-        "a𐄁bc"-      ],-      "tags": [-        "function",-        "search"-      ]-    },-    {-      "name": "functions, search, dot matcher on \\u2028",-      "selector": "$[?search(@, '.')]",-      "document": [-        "
",-        "\r
\n",-        "\r",-        "\n",-        true,-        [],-        {}-      ],-      "result": [-        "
",-        "\r
\n"-      ],-      "tags": [-        "function",-        "search"-      ]-    },-    {-      "name": "functions, search, dot matcher on \\u2029",-      "selector": "$[?search(@, '.')]",-      "document": [-        "
",-        "\r
\n",-        "\r",-        "\n",-        true,-        [],-        {}-      ],-      "result": [-        "
",-        "\r
\n"-      ],-      "tags": [-        "function",-        "search"-      ]-    },-    {-      "name": "functions, search, result cannot be compared",-      "selector": "$[?search(@.a, 'a.*')==true]",-      "invalid_selector": true,-      "tags": [-        "function",-        "search"-      ]-    },-    {-      "name": "functions, search, too few params",-      "selector": "$[?search(@.a)]",-      "invalid_selector": true,-      "tags": [-        "function",-        "search"-      ]-    },-    {-      "name": "functions, search, too many params",-      "selector": "$[?search(@.a,@.b,@.c)]",-      "invalid_selector": true,-      "tags": [-        "function",-        "search"-      ]-    },-    {-      "name": "functions, search, arg is a function expression",-      "selector": "$.values[?search(@, value($..['regex']))]",-      "document": {-        "regex": "b.?b",-        "values": [-          "abc",-          "bcd",-          "bab",-          "bba",-          "bbab",-          "b",-          true,-          [],-          {}-        ]-      },-      "result": [-        "bab",-        "bba",-        "bbab"-      ],-      "tags": [-        "function",-        "search"-      ]-    },-    {-      "name": "functions, search, dot in character class",-      "selector": "$[?search(@, 'a[.b]c')]",-      "document": [-        "x abc y",-        "x a.c y",-        "x axc y"-      ],-      "result": [-        "x abc y",-        "x a.c y"-      ],-      "tags": [-        "function",-        "search"-      ]-    },-    {-      "name": "functions, search, escaped dot",-      "selector": "$[?search(@, 'a\\\\.c')]",-      "document": [-        "x abc y",-        "x a.c y",-        "x axc y"-      ],-      "result": [-        "x a.c y"-      ],-      "tags": [-        "function",-        "search"-      ]-    },-    {-      "name": "functions, search, escaped backslash before dot",-      "selector": "$[?search(@, 'a\\\\\\\\.c')]",-      "document": [-        "x abc y",-        "x a.c y",-        "x axc y",-        "x a\\
c y"-      ],-      "result": [-        "x a\\
c y"-      ],-      "tags": [-        "function",-        "search"-      ]-    },-    {-      "name": "functions, search, escaped left square bracket",-      "selector": "$[?search(@, 'a\\\\[.c')]",-      "document": [-        "x abc y",-        "x a.c y",-        "x a[
c y"-      ],-      "result": [-        "x a[
c y"-      ],-      "tags": [-        "function",-        "search"-      ]-    },-    {-      "name": "functions, search, escaped right square bracket",-      "selector": "$[?search(@, 'a[\\\\].]c')]",-      "document": [-        "x abc y",-        "x a.c y",-        "x a
c y",-        "x a]c y"-      ],-      "result": [-        "x a.c y",-        "x a]c y"-      ],-      "tags": [-        "function",-        "search"-      ]-    },-    {-      "name": "functions, value, single-value nodelist",-      "selector": "$[?value(@.*)==4]",-      "document": [-        [-          4-        ],-        {-          "foo": 4-        },-        [-          5-        ],-        {-          "foo": 5-        },-        4-      ],-      "result": [-        [-          4-        ],-        {-          "foo": 4-        }-      ],-      "tags": [-        "function",-        "value"-      ]-    },-    {-      "name": "functions, value, multi-value nodelist",-      "selector": "$[?value(@.*)==4]",-      "document": [-        [-          4,-          4-        ],-        {-          "foo": 4,-          "bar": 4-        }-      ],-      "result": [],-      "tags": [-        "function",-        "value"-      ]-    },-    {-      "name": "functions, value, too few params",-      "selector": "$[?value()==4]",-      "invalid_selector": true,-      "tags": [-        "function",-        "value"-      ]-    },-    {-      "name": "functions, value, too many params",-      "selector": "$[?value(@.a,@.b)==4]",-      "invalid_selector": true,-      "tags": [-        "function",-        "value"-      ]-    },-    {-      "name": "functions, value, result must be compared",-      "selector": "$[?value(@.a)]",-      "invalid_selector": true,-      "tags": [-        "function",-        "value"-      ]-    },-    {-      "name": "whitespace, filter, space between question mark and expression",-      "selector": "$[? @.a]",-      "document": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "b": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "b",-          "d": "e"-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, filter, newline between question mark and expression",-      "selector": "$[?\n@.a]",-      "document": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "b": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "b",-          "d": "e"-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, filter, tab between question mark and expression",-      "selector": "$[?\t@.a]",-      "document": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "b": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "b",-          "d": "e"-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, filter, return between question mark and expression",-      "selector": "$[?\r@.a]",-      "document": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "b": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "b",-          "d": "e"-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, filter, space between question mark and parenthesized expression",-      "selector": "$[? (@.a)]",-      "document": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "b": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "b",-          "d": "e"-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, filter, newline between question mark and parenthesized expression",-      "selector": "$[?\n(@.a)]",-      "document": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "b": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "b",-          "d": "e"-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, filter, tab between question mark and parenthesized expression",-      "selector": "$[?\t(@.a)]",-      "document": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "b": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "b",-          "d": "e"-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, filter, return between question mark and parenthesized expression",-      "selector": "$[?\r(@.a)]",-      "document": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "b": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "b",-          "d": "e"-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, filter, space between parenthesized expression and bracket",-      "selector": "$[?(@.a) ]",-      "document": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "b": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "b",-          "d": "e"-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, filter, newline between parenthesized expression and bracket",-      "selector": "$[?(@.a)\n]",-      "document": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "b": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "b",-          "d": "e"-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, filter, tab between parenthesized expression and bracket",-      "selector": "$[?(@.a)\t]",-      "document": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "b": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "b",-          "d": "e"-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, filter, return between parenthesized expression and bracket",-      "selector": "$[?(@.a)\r]",-      "document": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "b": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "b",-          "d": "e"-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, filter, space between bracket and question mark",-      "selector": "$[ ?@.a]",-      "document": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "b": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "b",-          "d": "e"-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, filter, newline between bracket and question mark",-      "selector": "$[\n?@.a]",-      "document": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "b": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "b",-          "d": "e"-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, filter, tab between bracket and question mark",-      "selector": "$[\t?@.a]",-      "document": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "b": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "b",-          "d": "e"-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, filter, return between bracket and question mark",-      "selector": "$[\r?@.a]",-      "document": [-        {-          "a": "b",-          "d": "e"-        },-        {-          "b": "c",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "b",-          "d": "e"-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, functions, space between function name and parenthesis",-      "selector": "$[?count (@.*)==1]",-      "invalid_selector": true,-      "tags": [-        "count",-        "function",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, functions, newline between function name and parenthesis",-      "selector": "$[?count\n(@.*)==1]",-      "invalid_selector": true,-      "tags": [-        "count",-        "function",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, functions, tab between function name and parenthesis",-      "selector": "$[?count\t(@.*)==1]",-      "invalid_selector": true,-      "tags": [-        "count",-        "function",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, functions, return between function name and parenthesis",-      "selector": "$[?count\r(@.*)==1]",-      "invalid_selector": true,-      "tags": [-        "count",-        "function",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, functions, space between parenthesis and arg",-      "selector": "$[?count( @.*)==1]",-      "document": [-        {-          "a": 1-        },-        {-          "b": 2-        },-        {-          "a": 2,-          "b": 1-        }-      ],-      "result": [-        {-          "a": 1-        },-        {-          "b": 2-        }-      ],-      "tags": [-        "count",-        "function",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, functions, newline between parenthesis and arg",-      "selector": "$[?count(\n@.*)==1]",-      "document": [-        {-          "a": 1-        },-        {-          "b": 2-        },-        {-          "a": 2,-          "b": 1-        }-      ],-      "result": [-        {-          "a": 1-        },-        {-          "b": 2-        }-      ],-      "tags": [-        "count",-        "function",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, functions, tab between parenthesis and arg",-      "selector": "$[?count(\t@.*)==1]",-      "document": [-        {-          "a": 1-        },-        {-          "b": 2-        },-        {-          "a": 2,-          "b": 1-        }-      ],-      "result": [-        {-          "a": 1-        },-        {-          "b": 2-        }-      ],-      "tags": [-        "count",-        "function",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, functions, return between parenthesis and arg",-      "selector": "$[?count(\r@.*)==1]",-      "document": [-        {-          "a": 1-        },-        {-          "b": 2-        },-        {-          "a": 2,-          "b": 1-        }-      ],-      "result": [-        {-          "a": 1-        },-        {-          "b": 2-        }-      ],-      "tags": [-        "count",-        "function",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, functions, space between arg and comma",-      "selector": "$[?search(@ ,'[a-z]+')]",-      "document": [-        "foo",-        "123"-      ],-      "result": [-        "foo"-      ],-      "tags": [-        "function",-        "search",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, functions, newline between arg and comma",-      "selector": "$[?search(@\n,'[a-z]+')]",-      "document": [-        "foo",-        "123"-      ],-      "result": [-        "foo"-      ],-      "tags": [-        "function",-        "search",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, functions, tab between arg and comma",-      "selector": "$[?search(@\t,'[a-z]+')]",-      "document": [-        "foo",-        "123"-      ],-      "result": [-        "foo"-      ],-      "tags": [-        "function",-        "search",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, functions, return between arg and comma",-      "selector": "$[?search(@\r,'[a-z]+')]",-      "document": [-        "foo",-        "123"-      ],-      "result": [-        "foo"-      ],-      "tags": [-        "function",-        "search",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, functions, space between comma and arg",-      "selector": "$[?search(@, '[a-z]+')]",-      "document": [-        "foo",-        "123"-      ],-      "result": [-        "foo"-      ],-      "tags": [-        "function",-        "search",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, functions, newline between comma and arg",-      "selector": "$[?search(@,\n'[a-z]+')]",-      "document": [-        "foo",-        "123"-      ],-      "result": [-        "foo"-      ],-      "tags": [-        "function",-        "search",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, functions, tab between comma and arg",-      "selector": "$[?search(@,\t'[a-z]+')]",-      "document": [-        "foo",-        "123"-      ],-      "result": [-        "foo"-      ],-      "tags": [-        "function",-        "search",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, functions, return between comma and arg",-      "selector": "$[?search(@,\r'[a-z]+')]",-      "document": [-        "foo",-        "123"-      ],-      "result": [-        "foo"-      ],-      "tags": [-        "function",-        "search",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, functions, space between arg and parenthesis",-      "selector": "$[?count(@.* )==1]",-      "document": [-        {-          "a": 1-        },-        {-          "b": 2-        },-        {-          "a": 2,-          "b": 1-        }-      ],-      "result": [-        {-          "a": 1-        },-        {-          "b": 2-        }-      ],-      "tags": [-        "function",-        "search",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, functions, newline between arg and parenthesis",-      "selector": "$[?count(@.*\n)==1]",-      "document": [-        {-          "a": 1-        },-        {-          "b": 2-        },-        {-          "a": 2,-          "b": 1-        }-      ],-      "result": [-        {-          "a": 1-        },-        {-          "b": 2-        }-      ],-      "tags": [-        "count",-        "function",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, functions, tab between arg and parenthesis",-      "selector": "$[?count(@.*\t)==1]",-      "document": [-        {-          "a": 1-        },-        {-          "b": 2-        },-        {-          "a": 2,-          "b": 1-        }-      ],-      "result": [-        {-          "a": 1-        },-        {-          "b": 2-        }-      ],-      "tags": [-        "count",-        "function",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, functions, return between arg and parenthesis",-      "selector": "$[?count(@.*\r)==1]",-      "document": [-        {-          "a": 1-        },-        {-          "b": 2-        },-        {-          "a": 2,-          "b": 1-        }-      ],-      "result": [-        {-          "a": 1-        },-        {-          "b": 2-        }-      ],-      "tags": [-        "count",-        "function",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, functions, spaces in a relative singular selector",-      "selector": "$[?length(@ .a .b) == 3]",-      "document": [-        {-          "a": {-            "b": "foo"-          }-        },-        {}-      ],-      "result": [-        {-          "a": {-            "b": "foo"-          }-        }-      ],-      "tags": [-        "function",-        "length",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, functions, newlines in a relative singular selector",-      "selector": "$[?length(@\n.a\n.b) == 3]",-      "document": [-        {-          "a": {-            "b": "foo"-          }-        },-        {}-      ],-      "result": [-        {-          "a": {-            "b": "foo"-          }-        }-      ],-      "tags": [-        "function",-        "length",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, functions, tabs in a relative singular selector",-      "selector": "$[?length(@\t.a\t.b) == 3]",-      "document": [-        {-          "a": {-            "b": "foo"-          }-        },-        {}-      ],-      "result": [-        {-          "a": {-            "b": "foo"-          }-        }-      ],-      "tags": [-        "function",-        "length",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, functions, returns in a relative singular selector",-      "selector": "$[?length(@\r.a\r.b) == 3]",-      "document": [-        {-          "a": {-            "b": "foo"-          }-        },-        {}-      ],-      "result": [-        {-          "a": {-            "b": "foo"-          }-        }-      ],-      "tags": [-        "function",-        "length",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, functions, spaces in an absolute singular selector",-      "selector": "$..[?length(@)==length($ [0] .a)]",-      "document": [-        {-          "a": "foo"-        },-        {}-      ],-      "result": [-        "foo"-      ],-      "tags": [-        "function",-        "length",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, functions, newlines in an absolute singular selector",-      "selector": "$..[?length(@)==length($\n[0]\n.a)]",-      "document": [-        {-          "a": "foo"-        },-        {}-      ],-      "result": [-        "foo"-      ],-      "tags": [-        "function",-        "length",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, functions, tabs in an absolute singular selector",-      "selector": "$..[?length(@)==length($\t[0]\t.a)]",-      "document": [-        {-          "a": "foo"-        },-        {}-      ],-      "result": [-        "foo"-      ],-      "tags": [-        "function",-        "length",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, functions, returns in an absolute singular selector",-      "selector": "$..[?length(@)==length($\r[0]\r.a)]",-      "document": [-        {-          "a": "foo"-        },-        {}-      ],-      "result": [-        "foo"-      ],-      "tags": [-        "function",-        "length",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, space before ||",-      "selector": "$[?@.a ||@.b]",-      "document": [-        {-          "a": 1-        },-        {-          "b": 2-        },-        {-          "c": 3-        }-      ],-      "result": [-        {-          "a": 1-        },-        {-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, newline before ||",-      "selector": "$[?@.a\n||@.b]",-      "document": [-        {-          "a": 1-        },-        {-          "b": 2-        },-        {-          "c": 3-        }-      ],-      "result": [-        {-          "a": 1-        },-        {-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, tab before ||",-      "selector": "$[?@.a\t||@.b]",-      "document": [-        {-          "a": 1-        },-        {-          "b": 2-        },-        {-          "c": 3-        }-      ],-      "result": [-        {-          "a": 1-        },-        {-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, return before ||",-      "selector": "$[?@.a\r||@.b]",-      "document": [-        {-          "a": 1-        },-        {-          "b": 2-        },-        {-          "c": 3-        }-      ],-      "result": [-        {-          "a": 1-        },-        {-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, space after ||",-      "selector": "$[?@.a|| @.b]",-      "document": [-        {-          "a": 1-        },-        {-          "b": 2-        },-        {-          "c": 3-        }-      ],-      "result": [-        {-          "a": 1-        },-        {-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, newline after ||",-      "selector": "$[?@.a||\n@.b]",-      "document": [-        {-          "a": 1-        },-        {-          "b": 2-        },-        {-          "c": 3-        }-      ],-      "result": [-        {-          "a": 1-        },-        {-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, tab after ||",-      "selector": "$[?@.a||\t@.b]",-      "document": [-        {-          "a": 1-        },-        {-          "b": 2-        },-        {-          "c": 3-        }-      ],-      "result": [-        {-          "a": 1-        },-        {-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, return after ||",-      "selector": "$[?@.a||\r@.b]",-      "document": [-        {-          "a": 1-        },-        {-          "b": 2-        },-        {-          "c": 3-        }-      ],-      "result": [-        {-          "a": 1-        },-        {-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, space before &&",-      "selector": "$[?@.a &&@.b]",-      "document": [-        {-          "a": 1-        },-        {-          "b": 2-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, newline before &&",-      "selector": "$[?@.a\n&&@.b]",-      "document": [-        {-          "a": 1-        },-        {-          "b": 2-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, tab before &&",-      "selector": "$[?@.a\t&&@.b]",-      "document": [-        {-          "a": 1-        },-        {-          "b": 2-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, return before &&",-      "selector": "$[?@.a\r&&@.b]",-      "document": [-        {-          "a": 1-        },-        {-          "b": 2-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, space after &&",-      "selector": "$[?@.a&& @.b]",-      "document": [-        {-          "a": 1-        },-        {-          "b": 2-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, newline after &&",-      "selector": "$[?@.a&& @.b]",-      "document": [-        {-          "a": 1-        },-        {-          "b": 2-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, tab after &&",-      "selector": "$[?@.a&& @.b]",-      "document": [-        {-          "a": 1-        },-        {-          "b": 2-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, return after &&",-      "selector": "$[?@.a&& @.b]",-      "document": [-        {-          "a": 1-        },-        {-          "b": 2-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, space before ==",-      "selector": "$[?@.a ==@.b]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 1-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, newline before ==",-      "selector": "$[?@.a\n==@.b]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 1-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, tab before ==",-      "selector": "$[?@.a\t==@.b]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 1-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, return before ==",-      "selector": "$[?@.a\r==@.b]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 1-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, space after ==",-      "selector": "$[?@.a== @.b]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 1-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, newline after ==",-      "selector": "$[?@.a==\n@.b]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 1-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, tab after ==",-      "selector": "$[?@.a==\t@.b]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 1-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, return after ==",-      "selector": "$[?@.a==\r@.b]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 1-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, space before !=",-      "selector": "$[?@.a !=@.b]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, newline before !=",-      "selector": "$[?@.a\n!=@.b]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, tab before !=",-      "selector": "$[?@.a\t!=@.b]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, return before !=",-      "selector": "$[?@.a\r!=@.b]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, space after !=",-      "selector": "$[?@.a!= @.b]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, newline after !=",-      "selector": "$[?@.a!=\n@.b]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, tab after !=",-      "selector": "$[?@.a!=\t@.b]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, return after !=",-      "selector": "$[?@.a!=\r@.b]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, space before <",-      "selector": "$[?@.a <@.b]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, newline before <",-      "selector": "$[?@.a\n<@.b]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, tab before <",-      "selector": "$[?@.a\t<@.b]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, return before <",-      "selector": "$[?@.a\r<@.b]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, space after <",-      "selector": "$[?@.a< @.b]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, newline after <",-      "selector": "$[?@.a<\n@.b]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, tab after <",-      "selector": "$[?@.a<\t@.b]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, return after <",-      "selector": "$[?@.a<\r@.b]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, space before >",-      "selector": "$[?@.b >@.a]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, newline before >",-      "selector": "$[?@.b\n>@.a]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, tab before >",-      "selector": "$[?@.b\t>@.a]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, return before >",-      "selector": "$[?@.b\r>@.a]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, space after >",-      "selector": "$[?@.b> @.a]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, newline after >",-      "selector": "$[?@.b>\n@.a]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, tab after >",-      "selector": "$[?@.b>\t@.a]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, return after >",-      "selector": "$[?@.b>\r@.a]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, space before <=",-      "selector": "$[?@.a <=@.b]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        },-        {-          "a": 2,-          "b": 1-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, newline before <=",-      "selector": "$[?@.a\n<=@.b]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        },-        {-          "a": 2,-          "b": 1-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, tab before <=",-      "selector": "$[?@.a\t<=@.b]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        },-        {-          "a": 2,-          "b": 1-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, return before <=",-      "selector": "$[?@.a\r<=@.b]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        },-        {-          "a": 2,-          "b": 1-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, space after <=",-      "selector": "$[?@.a<= @.b]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        },-        {-          "a": 2,-          "b": 1-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, newline after <=",-      "selector": "$[?@.a<=\n@.b]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        },-        {-          "a": 2,-          "b": 1-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, tab after <=",-      "selector": "$[?@.a<=\t@.b]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        },-        {-          "a": 2,-          "b": 1-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, return after <=",-      "selector": "$[?@.a<=\r@.b]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        },-        {-          "a": 2,-          "b": 1-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, space before >=",-      "selector": "$[?@.b >=@.a]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        },-        {-          "a": 2,-          "b": 1-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, newline before >=",-      "selector": "$[?@.b\n>=@.a]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        },-        {-          "a": 2,-          "b": 1-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, tab before >=",-      "selector": "$[?@.b\t>=@.a]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        },-        {-          "a": 2,-          "b": 1-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, return before >=",-      "selector": "$[?@.b\r>=@.a]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        },-        {-          "a": 2,-          "b": 1-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, space after >=",-      "selector": "$[?@.b>= @.a]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        },-        {-          "a": 2,-          "b": 1-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, newline after >=",-      "selector": "$[?@.b>=\n@.a]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        },-        {-          "a": 2,-          "b": 1-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, tab after >=",-      "selector": "$[?@.b>=\t@.a]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        },-        {-          "a": 2,-          "b": 1-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, return after >=",-      "selector": "$[?@.b>=\r@.a]",-      "document": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        },-        {-          "a": 2,-          "b": 1-        }-      ],-      "result": [-        {-          "a": 1,-          "b": 1-        },-        {-          "a": 1,-          "b": 2-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, space between logical not and test expression",-      "selector": "$[?! @.a]",-      "document": [-        {-          "a": "a",-          "d": "e"-        },-        {-          "d": "f"-        },-        {-          "a": "d",-          "d": "f"-        }-      ],-      "result": [-        {-          "d": "f"-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, newline between logical not and test expression",-      "selector": "$[?!\n@.a]",-      "document": [-        {-          "a": "a",-          "d": "e"-        },-        {-          "d": "f"-        },-        {-          "a": "d",-          "d": "f"-        }-      ],-      "result": [-        {-          "d": "f"-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, tab between logical not and test expression",-      "selector": "$[?!\t@.a]",-      "document": [-        {-          "a": "a",-          "d": "e"-        },-        {-          "d": "f"-        },-        {-          "a": "d",-          "d": "f"-        }-      ],-      "result": [-        {-          "d": "f"-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, return between logical not and test expression",-      "selector": "$[?!\r@.a]",-      "document": [-        {-          "a": "a",-          "d": "e"-        },-        {-          "d": "f"-        },-        {-          "a": "d",-          "d": "f"-        }-      ],-      "result": [-        {-          "d": "f"-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, space between logical not and parenthesized expression",-      "selector": "$[?! (@.a=='b')]",-      "document": [-        {-          "a": "a",-          "d": "e"-        },-        {-          "a": "b",-          "d": "f"-        },-        {-          "a": "d",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "a",-          "d": "e"-        },-        {-          "a": "d",-          "d": "f"-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, newline between logical not and parenthesized expression",-      "selector": "$[?!\n(@.a=='b')]",-      "document": [-        {-          "a": "a",-          "d": "e"-        },-        {-          "a": "b",-          "d": "f"-        },-        {-          "a": "d",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "a",-          "d": "e"-        },-        {-          "a": "d",-          "d": "f"-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, tab between logical not and parenthesized expression",-      "selector": "$[?!\t(@.a=='b')]",-      "document": [-        {-          "a": "a",-          "d": "e"-        },-        {-          "a": "b",-          "d": "f"-        },-        {-          "a": "d",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "a",-          "d": "e"-        },-        {-          "a": "d",-          "d": "f"-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, operators, return between logical not and parenthesized expression",-      "selector": "$[?!\r(@.a=='b')]",-      "document": [-        {-          "a": "a",-          "d": "e"-        },-        {-          "a": "b",-          "d": "f"-        },-        {-          "a": "d",-          "d": "f"-        }-      ],-      "result": [-        {-          "a": "a",-          "d": "e"-        },-        {-          "a": "d",-          "d": "f"-        }-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, selectors, space between root and bracket",-      "selector": "$ ['a']",-      "document": {-        "a": "ab"-      },-      "result": [-        "ab"-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, selectors, newline between root and bracket",-      "selector": "$\n['a']",-      "document": {-        "a": "ab"-      },-      "result": [-        "ab"-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, selectors, tab between root and bracket",-      "selector": "$\t['a']",-      "document": {-        "a": "ab"-      },-      "result": [-        "ab"-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, selectors, return between root and bracket",-      "selector": "$\r['a']",-      "document": {-        "a": "ab"-      },-      "result": [-        "ab"-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, selectors, space between bracket and bracket",-      "selector": "$['a'] ['b']",-      "document": {-        "a": {-          "b": "ab"-        }-      },-      "result": [-        "ab"-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, selectors, newline between bracket and bracket",-      "selector": "$['a'] \n['b']",-      "document": {-        "a": {-          "b": "ab"-        }-      },-      "result": [-        "ab"-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, selectors, tab between bracket and bracket",-      "selector": "$['a'] \t['b']",-      "document": {-        "a": {-          "b": "ab"-        }-      },-      "result": [-        "ab"-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, selectors, return between bracket and bracket",-      "selector": "$['a'] \r['b']",-      "document": {-        "a": {-          "b": "ab"-        }-      },-      "result": [-        "ab"-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, selectors, space between root and dot",-      "selector": "$ .a",-      "document": {-        "a": "ab"-      },-      "result": [-        "ab"-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, selectors, newline between root and dot",-      "selector": "$\n.a",-      "document": {-        "a": "ab"-      },-      "result": [-        "ab"-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, selectors, tab between root and dot",-      "selector": "$\t.a",-      "document": {-        "a": "ab"-      },-      "result": [-        "ab"-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, selectors, return between root and dot",-      "selector": "$\r.a",-      "document": {-        "a": "ab"-      },-      "result": [-        "ab"-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, selectors, space between dot and name",-      "selector": "$. a",-      "invalid_selector": true,-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, selectors, newline between dot and name",-      "selector": "$.\na",-      "invalid_selector": true,-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, selectors, tab between dot and name",-      "selector": "$.\ta",-      "invalid_selector": true,-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, selectors, return between dot and name",-      "selector": "$.\ra",-      "invalid_selector": true,-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, selectors, space between recursive descent and name",-      "selector": "$.. a",-      "invalid_selector": true,-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, selectors, newline between recursive descent and name",-      "selector": "$..\na",-      "invalid_selector": true,-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, selectors, tab between recursive descent and name",-      "selector": "$..\ta",-      "invalid_selector": true,-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, selectors, return between recursive descent and name",-      "selector": "$..\ra",-      "invalid_selector": true,-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, selectors, space between bracket and selector",-      "selector": "$[ 'a']",-      "document": {-        "a": "ab"-      },-      "result": [-        "ab"-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, selectors, newline between bracket and selector",-      "selector": "$[\n'a']",-      "document": {-        "a": "ab"-      },-      "result": [-        "ab"-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, selectors, tab between bracket and selector",-      "selector": "$[\t'a']",-      "document": {-        "a": "ab"-      },-      "result": [-        "ab"-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, selectors, return between bracket and selector",-      "selector": "$[\r'a']",-      "document": {-        "a": "ab"-      },-      "result": [-        "ab"-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, selectors, space between selector and bracket",-      "selector": "$['a' ]",-      "document": {-        "a": "ab"-      },-      "result": [-        "ab"-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, selectors, newline between selector and bracket",-      "selector": "$['a'\n]",-      "document": {-        "a": "ab"-      },-      "result": [-        "ab"-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, selectors, tab between selector and bracket",-      "selector": "$['a'\t]",-      "document": {-        "a": "ab"-      },-      "result": [-        "ab"-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, selectors, return between selector and bracket",-      "selector": "$['a'\r]",-      "document": {-        "a": "ab"-      },-      "result": [-        "ab"-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, selectors, space between selector and comma",-      "selector": "$['a' ,'b']",-      "document": {-        "a": "ab",-        "b": "bc"-      },-      "result": [-        "ab",-        "bc"-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, selectors, newline between selector and comma",-      "selector": "$['a'\n,'b']",-      "document": {-        "a": "ab",-        "b": "bc"-      },-      "result": [-        "ab",-        "bc"-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, selectors, tab between selector and comma",-      "selector": "$['a'\t,'b']",-      "document": {-        "a": "ab",-        "b": "bc"-      },-      "result": [-        "ab",-        "bc"-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, selectors, return between selector and comma",-      "selector": "$['a'\r,'b']",-      "document": {-        "a": "ab",-        "b": "bc"-      },-      "result": [-        "ab",-        "bc"-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, selectors, space between comma and selector",-      "selector": "$['a', 'b']",-      "document": {-        "a": "ab",-        "b": "bc"-      },-      "result": [-        "ab",-        "bc"-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, selectors, newline between comma and selector",-      "selector": "$['a',\n'b']",-      "document": {-        "a": "ab",-        "b": "bc"-      },-      "result": [-        "ab",-        "bc"-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, selectors, tab between comma and selector",-      "selector": "$['a',\t'b']",-      "document": {-        "a": "ab",-        "b": "bc"-      },-      "result": [-        "ab",-        "bc"-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, selectors, return between comma and selector",-      "selector": "$['a',\r'b']",-      "document": {-        "a": "ab",-        "b": "bc"-      },-      "result": [-        "ab",-        "bc"-      ],-      "tags": [-        "whitespace"-      ]-    },-    {-      "name": "whitespace, slice, space between start and colon",-      "selector": "$[1 :5:2]",-      "document": [-        1,-        2,-        3,-        4,-        5,-        6-      ],-      "result": [-        2,-        4-      ],-      "tags": [-        "index",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, slice, newline between start and colon",-      "selector": "$[1\n:5:2]",-      "document": [-        1,-        2,-        3,-        4,-        5,-        6-      ],-      "result": [-        2,-        4-      ],-      "tags": [-        "index",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, slice, tab between start and colon",-      "selector": "$[1\t:5:2]",-      "document": [-        1,-        2,-        3,-        4,-        5,-        6-      ],-      "result": [-        2,-        4-      ],-      "tags": [-        "index",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, slice, return between start and colon",-      "selector": "$[1\r:5:2]",-      "document": [-        1,-        2,-        3,-        4,-        5,-        6-      ],-      "result": [-        2,-        4-      ],-      "tags": [-        "index",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, slice, space between colon and end",-      "selector": "$[1: 5:2]",-      "document": [-        1,-        2,-        3,-        4,-        5,-        6-      ],-      "result": [-        2,-        4-      ],-      "tags": [-        "index",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, slice, newline between colon and end",-      "selector": "$[1:\n5:2]",-      "document": [-        1,-        2,-        3,-        4,-        5,-        6-      ],-      "result": [-        2,-        4-      ],-      "tags": [-        "index",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, slice, tab between colon and end",-      "selector": "$[1:\t5:2]",-      "document": [-        1,-        2,-        3,-        4,-        5,-        6-      ],-      "result": [-        2,-        4-      ],-      "tags": [-        "index",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, slice, return between colon and end",-      "selector": "$[1:\r5:2]",-      "document": [-        1,-        2,-        3,-        4,-        5,-        6-      ],-      "result": [-        2,-        4-      ],-      "tags": [-        "index",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, slice, space between end and colon",-      "selector": "$[1:5 :2]",-      "document": [-        1,-        2,-        3,-        4,-        5,-        6-      ],-      "result": [-        2,-        4-      ],-      "tags": [-        "index",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, slice, newline between end and colon",-      "selector": "$[1:5\n:2]",-      "document": [-        1,-        2,-        3,-        4,-        5,-        6-      ],-      "result": [-        2,-        4-      ],-      "tags": [-        "index",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, slice, tab between end and colon",-      "selector": "$[1:5\t:2]",-      "document": [-        1,-        2,-        3,-        4,-        5,-        6-      ],-      "result": [-        2,-        4-      ],-      "tags": [-        "index",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, slice, return between end and colon",-      "selector": "$[1:5\r:2]",-      "document": [-        1,-        2,-        3,-        4,-        5,-        6-      ],-      "result": [-        2,-        4-      ],-      "tags": [-        "index",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, slice, space between colon and step",-      "selector": "$[1:5: 2]",-      "document": [-        1,-        2,-        3,-        4,-        5,-        6-      ],-      "result": [-        2,-        4-      ],-      "tags": [-        "index",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, slice, newline between colon and step",-      "selector": "$[1:5:\n2]",-      "document": [-        1,-        2,-        3,-        4,-        5,-        6-      ],-      "result": [-        2,-        4-      ],-      "tags": [-        "index",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, slice, tab between colon and step",-      "selector": "$[1:5:\t2]",-      "document": [-        1,-        2,-        3,-        4,-        5,-        6-      ],-      "result": [-        2,-        4-      ],-      "tags": [-        "index",-        "whitespace"-      ]-    },-    {-      "name": "whitespace, slice, return between colon and step",-      "selector": "$[1:5:\r2]",-      "document": [-        1,-        2,-        3,-        4,-        5,-        6-      ],-      "result": [-        2,-        4-      ],-      "tags": [-        "index",-        "whitespace"-      ]-    }-  ]-}
+ test/spec/LocatedSpec.hs view
@@ -0,0 +1,144 @@+module LocatedSpec+  ( spec )+  where++import qualified Data.Aeson        as JSON+import qualified Data.Vector       as V++import Data.Aeson.JSONPath  (queryLocatedQQ, jsonPath)+import Data.Aeson.QQ.Simple (aesonQQ)+import Data.Aeson           (Value)+import Data.Vector          (Vector)+import Test.Hspec++import Prelude++getVector :: Value -> Vector Value+getVector (JSON.Array arr) = arr+getVector _ = V.empty++-- taken from https://serdejsonpath.live/+rootDoc :: Value+rootDoc = [aesonQQ|{+    "store": {+      "books": [+        {+          "title": "Guns, Germs, and Steel",+          "author": "Jared Diamond",+          "category": "reference",+          "price": 24.99+        },+        {+          "title": "David Copperfield",+          "author": "Charles Dickens",+          "category": "fiction",+          "price": 12.99+        },+        {+          "title": "Moby Dick",+          "author": "Herman Melville",+          "category": "fiction",+          "price": 8.99+        },+        {+          "title": "Crime and Punishment",+          "author": "Fyodor Dostoevsky",+          "category": "fiction",+          "price": 19.99+        }+      ]+    }+  }|]+++storeDoc :: Value+storeDoc = [aesonQQ|+  {+    "books": [+      {+        "title": "Guns, Germs, and Steel",+        "author": "Jared Diamond",+        "category": "reference",+        "price": 24.99+      },+      {+        "title": "David Copperfield",+        "author": "Charles Dickens",+        "category": "fiction",+        "price": 12.99+      },+      {+        "title": "Moby Dick",+        "author": "Herman Melville",+        "category": "fiction",+        "price": 8.99+      },+      {+        "title": "Crime and Punishment",+        "author": "Fyodor Dostoevsky",+        "category": "fiction",+        "price": 19.99+      }+    ]+  }|]++booksDoc :: Value+booksDoc = [aesonQQ| [+      {+        "title": "Guns, Germs, and Steel",+        "author": "Jared Diamond",+        "category": "reference",+        "price": 24.99+      },+      {+        "title": "David Copperfield",+        "author": "Charles Dickens",+        "category": "fiction",+        "price": 12.99+      },+      {+        "title": "Moby Dick",+        "author": "Herman Melville",+        "category": "fiction",+        "price": 8.99+      },+      {+        "title": "Crime and Punishment",+        "author": "Fyodor Dostoevsky",+        "category": "fiction",+        "price": 19.99+      }+  ]|]+++books0Doc :: Value+books0Doc = [aesonQQ|[+      {+        "title": "Guns, Germs, and Steel",+        "author": "Jared Diamond",+        "category": "reference",+        "price": 24.99+      }+  ]|]+++spec :: Spec+spec = do+  describe "test queryLocated" $ do+    it "returns root document when query is $" $+      queryLocatedQQ [jsonPath|$|] rootDoc `shouldBe` V.singleton ("$",rootDoc)++    it "returns store object when queryQQ is $.store" $+      queryLocatedQQ [jsonPath|$.store|] rootDoc `shouldBe` V.fromList [("$['store']",storeDoc)]++    it "returns store object when queryQQ is $['store']" $+      queryLocatedQQ [jsonPath|$['store']|] rootDoc `shouldBe` V.fromList [("$['store']",storeDoc)]++    it "returns books array when queryQQ is $.store.books" $+      queryLocatedQQ [jsonPath|$.store.books|] rootDoc `shouldBe` V.fromList [("$['store']['books']",booksDoc)]++    it "returns 0-index book item, $.store.books[0]" $+      queryLocatedQQ [jsonPath|$.store.books[0]|] rootDoc `shouldBe` V.zip (V.singleton "$['store']['books'][0]") (getVector books0Doc)++    it "returns 0-index book item, $.store.books[-4]" $+      queryLocatedQQ [jsonPath|$.store.books[-4]|] rootDoc `shouldBe` V.zip (V.singleton "$['store']['books'][0]") (getVector books0Doc)
+ test/spec/Main.hs view
@@ -0,0 +1,29 @@+module Main+  ( main )+  where++import qualified Test.Hspec as HS++import qualified ParserSpec+import qualified QuerySpec+import qualified LocatedSpec++import Test.Hspec.Runner+import Prelude++specs :: Spec+specs = do+  HS.describe "Run all tests" $ do+    ParserSpec.spec+    QuerySpec.spec+    LocatedSpec.spec+++main :: IO ()+main = do+  summary <- hspecWithResult defaultConfig +    { configColorMode = ColorAuto+    } specs+  +  putStrLn $ "Total tests: " ++ show (summaryExamples summary)+  putStrLn $ "Failures: "    ++ show (summaryFailures summary)
+ test/spec/ParserSpec.hs view
@@ -0,0 +1,443 @@+module ParserSpec+  ( spec )+  where++import qualified Text.ParserCombinators.Parsec as P++import Data.Aeson.JSONPath.Parser       (pQuery)+import Data.Either                      (isLeft)++import Data.Aeson.JSONPath.Types+import Test.Hspec++import Prelude++spec :: Spec+spec = do+  describe "Parse query string" $ do+    it "parses query: $" $+      P.parse pQuery "" "$"+      `shouldBe`+      Right (Query{queryType=Root,querySegments=[]})++    it "parses query: $.store" $+      P.parse pQuery "" "$.store"+      `shouldBe`+      Right Query {+        queryType = Root,+        querySegments = [QuerySegment {+          segmentType = Child,+          segment = Dotted "store"+        }]+      }++    it "parses query: $['store']" $+      P.parse pQuery "" "$['store']"+      `shouldBe`+      Right Query {+        queryType = Root,+        querySegments = [QuerySegment {+          segmentType = Child,+          segment = Bracketed [Name "store"]+        }]+      }++    it "parses query: $.store.books" $+      P.parse pQuery "" "$.store.books"+      `shouldBe`+      Right Query {+        queryType = Root,+        querySegments = [QuerySegment {+          segmentType = Child,+          segment = Dotted "store"+          }, QuerySegment {+          segmentType = Child,+          segment = Dotted "books"+        }]+      }++    it "parses query: $.store.books[0]" $+      P.parse pQuery "" "$.store.books[0]"+      `shouldBe`+      Right Query {+        queryType = Root,+        querySegments = [QuerySegment {+          segmentType = Child,+          segment = Dotted "store"+        }, QuerySegment {+          segmentType = Child,+          segment = Dotted "books"+        }, QuerySegment {+          segmentType = Child,+          segment = Bracketed [Index 0]+        }]+      }++    it "parses query: $.store.books[0,2]" $+      P.parse pQuery "" "$.store.books[0,2]"+      `shouldBe`+      Right Query {+        queryType = Root,+        querySegments = [QuerySegment {+          segmentType = Child,+          segment = Dotted "store"+        }, QuerySegment {+          segmentType = Child,+          segment = Dotted "books"+        }, QuerySegment {+          segmentType = Child,+          segment = Bracketed [Index 0, Index 2]+        }]+      }++    it "parses query: $.store.books[1:3]" $+      P.parse pQuery "" "$.store.books[1:3]"+      `shouldBe`+      Right Query {+        queryType = Root,+        querySegments = [QuerySegment {+          segmentType = Child,+          segment = Dotted "store"+        }, QuerySegment {+          segmentType = Child,+          segment = Dotted "books"+        }, QuerySegment {+          segmentType = Child,+          segment = Bracketed [ArraySlice (Just 1, Just 3, 1)]+        }]+      }++    it "parses query: $.store.books[1:4:2]" $+      P.parse pQuery "" "$.store.books[1:4:2]"+      `shouldBe`+      Right Query {+        queryType = Root,+        querySegments = [QuerySegment {+          segmentType = Child,+          segment = Dotted "store"+        }, QuerySegment {+          segmentType = Child,+          segment = Dotted "books"+        }, QuerySegment {+          segmentType = Child,+          segment = Bracketed [ArraySlice (Just 1, Just 4, 2)]+        }]+      }++    it "parses query: $.store.books[-1:-4:-2]" $+      P.parse pQuery "" "$.store.books[-1:-4:-2]"+      `shouldBe`+      Right Query {+        queryType = Root,+        querySegments = [QuerySegment {+          segmentType = Child,+          segment = Dotted "store"+        }, QuerySegment {+          segmentType = Child,+          segment = Dotted "books"+        }, QuerySegment {+          segmentType = Child,+          segment = Bracketed [ArraySlice (Just (-1), Just (-4), (-2))]+        }]+      }++    it "parses query: $.store.books[1:3, 0, 1]" $+      P.parse pQuery "" "$.store.books[1:3, 0, 1]"+      `shouldBe`+      Right Query {+        queryType = Root,+        querySegments = [QuerySegment {+          segmentType = Child,+          segment = Dotted "store"+        }, QuerySegment {+          segmentType = Child,+          segment = Dotted "books"+        }, QuerySegment {+          segmentType = Child,+          segment = Bracketed [ArraySlice (Just 1, Just 3, 1), Index 0, Index 1]+        }]+      }++    it "parses query: $.*" $+      P.parse pQuery "" "$.*" +      `shouldBe` +      Right Query {+        queryType = Root,+        querySegments = [QuerySegment {+          segmentType = Child,+          segment = WildcardSegment+        }]+      }++    it "parses query: $[*]" $+      P.parse pQuery "" "$[*]"+      `shouldBe`+      Right Query {+        queryType = Root,+        querySegments = [QuerySegment {+          segmentType = Child,+          segment = Bracketed [WildcardSelector]+        }]+      }++    it "parses query: $..*" $+      P.parse pQuery "" "$..*"+      `shouldBe`+      Right Query {+        queryType = Root,+        querySegments = [QuerySegment {+          segmentType = Descendant,+          segment = WildcardSegment+        }]+      }++    it "parses query: $..[*]" $+      P.parse pQuery "" "$..[*]"+      `shouldBe` +      Right Query {+        queryType = Root,+        querySegments = [QuerySegment {+          segmentType = Descendant,+          segment = Bracketed [WildcardSelector]+        }]+      }++    it "fails with $.1startsWithNum" $+      P.parse pQuery "" "$.1startsWithNum"+      `shouldSatisfy` isLeft++    it "parses query $.©®±×÷Ωπ•€→∀∃∈≠≤≥✓λ" $+      P.parse pQuery "" "$.©®±×÷Ωπ•€→∀∃∈≠≤≥✓λ"+      `shouldBe`+      Right Query {+        queryType = Root,+        querySegments = [QuerySegment {+          segmentType = Child,+          segment = Dotted "©®±×÷Ωπ•€→∀∃∈≠≤≥✓λ"+        }]+      }++    it "parses query: $._" $+      P.parse pQuery "" "$._"+      `shouldBe`+      Right Query {+        queryType = Root,+        querySegments = [QuerySegment {+          segmentType = Child,+          segment = Dotted "_"+        }]+      }++    it "parses query: $.underscore_key" $+      P.parse pQuery "" "$.underscore_key"+      `shouldBe`+      Right Query {+        queryType = Root,+        querySegments = [QuerySegment {+          segmentType = Child,+          segment = Dotted "underscore_key"+        }]+      }++    it "parses query: $[0,TAB/LINEFEED/RETURN/SPACE1]" $+      P.parse pQuery "" "$[0,\n\t\r 1]"+      `shouldBe`+      Right Query {+        queryType = Root,+        querySegments = [QuerySegment {+          segmentType = Child,+          segment = Bracketed [Index 0, Index 1]+        }]+      }++    describe "parses JSPFilter Query" $ do+      it "$[?@.category == 'reference']" $+        P.parse pQuery "" "$[?@.category == 'reference']"+        `shouldBe`+        Right Query {+          queryType = Root,+          querySegments = [QuerySegment {+            segmentType = Child,+            segment = Bracketed [Filter (LogicalOr [LogicalAnd [Comparison (Comp (CompSQ SingularQuery {+              singularQueryType = CurrentSQ,+              singularQuerySegments = [NameSQSeg "category"]+            }) Equal (CompLit (LitString "reference")))]])]+          }]+        }++      it "test expr: $..books[?@.price].title" $+        P.parse pQuery "" "$..books[?@.price].title"+        `shouldBe`+        Right Query {+          queryType = Root,+          querySegments = [QuerySegment {+            segmentType = Descendant,+            segment = Dotted "books"+          }, QuerySegment {+            segmentType = Child,+            segment = Bracketed [Filter (LogicalOr [LogicalAnd [Test (FilterQuery Query {+              queryType = Current,+              querySegments = [QuerySegment {+                segmentType = Child,+                segment = Dotted "price"+              }]+            })]])]+          }, QuerySegment {+            segmentType = Child,+            segment = Dotted "title"+          }]+        }++      it "and expr: $[?@.price < 20 && @.price > 10]" $+        P.parse pQuery "" "$[?@.price < 20 && @.price > 10]" +        `shouldBe`+        Right Query {+          queryType = Root,+          querySegments = [QuerySegment {+            segmentType = Child,+            segment = Bracketed [Filter (LogicalOr [LogicalAnd [Comparison (Comp (CompSQ SingularQuery {+              singularQueryType = CurrentSQ,+              singularQuerySegments = [NameSQSeg "price"]+            }) Less (CompLit (LitNum 20.0))), Comparison (Comp (CompSQ SingularQuery {+              singularQueryType = CurrentSQ,+              singularQuerySegments = [NameSQSeg "price"]+            }) Greater (CompLit (LitNum 10.0)))]])]+          }]+        }++      it "or expr: $[?@.price < 20 || @.price > 10]" $+        P.parse pQuery "" "$[?@.price < 20 || @.price > 10]"+        `shouldBe`+        Right Query {+          queryType = Root,+          querySegments = [QuerySegment {+            segmentType = Child,+            segment = Bracketed [Filter (LogicalOr [LogicalAnd [Comparison (Comp (CompSQ SingularQuery {+              singularQueryType = CurrentSQ,+              singularQuerySegments = [NameSQSeg "price"]+            }) Less (CompLit (LitNum 20.0)))], LogicalAnd [Comparison (Comp (CompSQ SingularQuery {+              singularQueryType = CurrentSQ,+              singularQuerySegments = [NameSQSeg "price"]+            }) Greater (CompLit (LitNum 10.0)))]])]+          }]+        }++      it "root filter: $..books[?$.price].title" $+        P.parse pQuery "" "$..books[?$.price].title"+        `shouldBe`+        Right Query {+          queryType = Root,+          querySegments = [QuerySegment {+            segmentType = Descendant,+            segment = Dotted "books"+          }, QuerySegment {+            segmentType = Child,+            segment = Bracketed [Filter (LogicalOr [LogicalAnd [Test (FilterQuery Query {+              queryType = Root,+              querySegments = [QuerySegment {+                segmentType = Child,+                segment = Dotted "price"+              }]+            })]])]+          }, QuerySegment {+            segmentType = Child,+            segment = Dotted "title"+          }]+        }++      it "not expr: $[?!(@.price < 20 && @.price > 10)]" $+        P.parse pQuery "" "$[?!(@.price < 20 && @.price > 10)]" +        `shouldBe`+        Right Query {+          queryType = Root,+          querySegments = [QuerySegment {+            segmentType = Child,+            segment = Bracketed [Filter (LogicalOr [LogicalAnd [NotParen (LogicalOr [LogicalAnd [Comparison (Comp (CompSQ SingularQuery {+              singularQueryType = CurrentSQ,+              singularQuerySegments = [NameSQSeg "price"]+            })  Less (CompLit (LitNum 20.0))), Comparison (Comp (CompSQ SingularQuery {+              singularQueryType = CurrentSQ,+              singularQuerySegments = [NameSQSeg "price"]+            }) Greater (CompLit (LitNum 10.0)))]])]])]+          }]+        }++      it "scientific: $.store.books[?@.price < -1e20]" $+        P.parse pQuery "" "$.store.books[?@['price'] < -1e20]"+        `shouldBe`+        Right Query {+          queryType = Root,+          querySegments = [QuerySegment {+            segmentType = Child,+            segment = Dotted "store"+          }, QuerySegment {+            segmentType = Child,+            segment = Dotted "books"+          }, QuerySegment {+            segmentType = Child,+            segment = Bracketed [Filter (LogicalOr [LogicalAnd [Comparison (Comp (CompSQ SingularQuery {+              singularQueryType = CurrentSQ,+              singularQuerySegments = [NameSQSeg "price"]+            }) Less (CompLit (LitNum (-1.0e20))))]])]+          }]+        }++      it "double: $.store.books[?@.price < 0.01]" $+        P.parse pQuery "" "$.store.books[?@['price'] < 0.01]"+        `shouldBe`+        Right Query {+          queryType = Root,+          querySegments = [QuerySegment {+            segmentType = Child,+            segment = Dotted "store"+          }, QuerySegment {+            segmentType = Child,+            segment = Dotted "books"+          }, QuerySegment {+            segmentType = Child,+            segment = Bracketed [Filter (LogicalOr [LogicalAnd [Comparison (Comp (CompSQ SingularQuery {+              singularQueryType = CurrentSQ,+              singularQuerySegments = [NameSQSeg "price"]+            }) Less (CompLit (LitNum (1.0e-2))))]])]+          }]+        }++      it "bool: $.store.books[?@.is_available == true]" $+        P.parse pQuery "" "$.store.books[?@.is_available == true]"+        `shouldBe`+        Right Query {+          queryType = Root,+          querySegments = [QuerySegment {+            segmentType = Child,+            segment = Dotted "store"+          }, QuerySegment {+            segmentType = Child,+            segment = Dotted "books"+          }, QuerySegment {+            segmentType = Child,+            segment = Bracketed [Filter (LogicalOr [LogicalAnd [Comparison (Comp (CompSQ SingularQuery {+              singularQueryType = CurrentSQ,+              singularQuerySegments = [NameSQSeg "is_available"]+            }) Equal (CompLit (LitBool True)))]])]+          }]+        }++      it "null: $.store.books[?@.is_available == null]" $+        P.parse pQuery "" "$.store.books[?@.is_available == null]"+        `shouldBe`+        Right Query {+          queryType = Root,+          querySegments = [QuerySegment {+            segmentType = Child,+            segment = Dotted "store"+          }, QuerySegment {+            segmentType = Child,+            segment = Dotted "books"+          }, QuerySegment {+            segmentType = Child,+            segment = Bracketed [Filter (LogicalOr [LogicalAnd [Comparison (Comp (CompSQ SingularQuery {+              singularQueryType = CurrentSQ,+              singularQuerySegments = [NameSQSeg "is_available"]+            }) Equal (CompLit LitNull))]])]+          }]+        }
+ test/spec/QuerySpec.hs view
@@ -0,0 +1,348 @@+module QuerySpec+  ( spec )+  where++import qualified Data.Vector       as V+import qualified Data.Aeson        as JSON++import Data.Aeson.QQ.Simple (aesonQQ)+import Data.Aeson           (Value)+import Data.Vector          (Vector)+import Test.Hspec++import Data.Aeson.JSONPath  (queryQQ, jsonPath)++import Prelude++getVector :: Value -> Vector Value+getVector (JSON.Array arr) = arr+getVector _ = V.empty++-- taken from https://serdejsonpath.live/+rootDoc :: Value+rootDoc = [aesonQQ|{+    "store": {+      "books": [+        {+          "title": "Guns, Germs, and Steel",+          "author": "Jared Diamond",+          "category": "reference",+          "price": 24.99+        },+        {+          "title": "David Copperfield",+          "author": "Charles Dickens",+          "category": "fiction",+          "price": 12.99+        },+        {+          "title": "Moby Dick",+          "author": "Herman Melville",+          "category": "fiction",+          "price": 8.99+        },+        {+          "title": "Crime and Punishment",+          "author": "Fyodor Dostoevsky",+          "category": "fiction",+          "price": 19.99+        }+      ]+    }+  }|]+++storeDoc :: Value+storeDoc = [aesonQQ|+  {+    "books": [+      {+        "title": "Guns, Germs, and Steel",+        "author": "Jared Diamond",+        "category": "reference",+        "price": 24.99+      },+      {+        "title": "David Copperfield",+        "author": "Charles Dickens",+        "category": "fiction",+        "price": 12.99+      },+      {+        "title": "Moby Dick",+        "author": "Herman Melville",+        "category": "fiction",+        "price": 8.99+      },+      {+        "title": "Crime and Punishment",+        "author": "Fyodor Dostoevsky",+        "category": "fiction",+        "price": 19.99+      }+    ]+  }|]++booksDoc :: Value+booksDoc = [aesonQQ| [+      {+        "title": "Guns, Germs, and Steel",+        "author": "Jared Diamond",+        "category": "reference",+        "price": 24.99+      },+      {+        "title": "David Copperfield",+        "author": "Charles Dickens",+        "category": "fiction",+        "price": 12.99+      },+      {+        "title": "Moby Dick",+        "author": "Herman Melville",+        "category": "fiction",+        "price": 8.99+      },+      {+        "title": "Crime and Punishment",+        "author": "Fyodor Dostoevsky",+        "category": "fiction",+        "price": 19.99+      }+  ]|]+++books0Doc :: Value+books0Doc = [aesonQQ|[+      {+        "title": "Guns, Germs, and Steel",+        "author": "Jared Diamond",+        "category": "reference",+        "price": 24.99+      }+  ]|]++books0And2Doc :: Value+books0And2Doc = [aesonQQ|[+      {+        "title": "Guns, Germs, and Steel",+        "author": "Jared Diamond",+        "category": "reference",+        "price": 24.99+      },+      {+        "title": "Moby Dick",+        "author": "Herman Melville",+        "category": "fiction",+        "price": 8.99+      }+  ]|]++books1To3Doc :: Value+books1To3Doc = [aesonQQ|[+      {+        "title": "David Copperfield",+        "author": "Charles Dickens",+        "category": "fiction",+        "price": 12.99+      },+      {+        "title": "Moby Dick",+        "author": "Herman Melville",+        "category": "fiction",+        "price": 8.99+      }+  ]|]++books1To3And0And1Doc :: Value+books1To3And0And1Doc = [aesonQQ|[+      {+        "title": "David Copperfield",+        "author": "Charles Dickens",+        "category": "fiction",+        "price": 12.99+      },+      {+        "title": "Moby Dick",+        "author": "Herman Melville",+        "category": "fiction",+        "price": 8.99+      },+      {+        "title": "Guns, Germs, and Steel",+        "author": "Jared Diamond",+        "category": "reference",+        "price": 24.99+      },+      {+        "title": "David Copperfield",+        "author": "Charles Dickens",+        "category": "fiction",+        "price": 12.99+      }+  ]|]++lessThanPrice20Books :: Value+lessThanPrice20Books = [aesonQQ| [+      {+        "title": "David Copperfield",+        "author": "Charles Dickens",+        "category": "fiction",+        "price": 12.99+      },+      {+        "title": "Moby Dick",+        "author": "Herman Melville",+        "category": "fiction",+        "price": 8.99+      },+      {+        "title": "Crime and Punishment",+        "author": "Fyodor Dostoevsky",+        "category": "fiction",+        "price": 19.99+      }+  ]|]++alphaArr :: Value+alphaArr = [aesonQQ| ["a","b","c","d","e","f","g"] |]++fgArr :: Value+fgArr = [aesonQQ| ["f","g"] |]++bdArr :: Value+bdArr = [aesonQQ| ["b","d"] |]++fdArr :: Value+fdArr = [aesonQQ| ["f","d"] |]++gfedcbaArr :: Value+gfedcbaArr = [aesonQQ| ["g","f","e","d","c","b","a"] |]++rfcExample1 :: Value+rfcExample1 = [aesonQQ| {+    "o": {"j": 1, "k": 2},+    "a": [5, 3, [{"j": 4}, {"k": 6}]]+  } |]++rfcExample1Desc :: Value+rfcExample1Desc = [aesonQQ| [+    [5, 3, [{"j": 4}, {"k": 6}]],+    {"j": 1, "k": 2},+    5,+    3,+    [{"j": 4}, {"k": 6}],+    {"j": 4},+    {"k": 6},+    4,+    6,+    1,+    2+  ]|]++boolsAndNulls :: Value+boolsAndNulls = [aesonQQ| [+    { "a": true },+    { "a": false },+    { "a": null }+  ]|]+++boolsAndNullsA :: Value+boolsAndNullsA = [aesonQQ| [{ "a": true }] |]++boolsAndNullsB :: Value+boolsAndNullsB = [aesonQQ| [{ "a": false }] |]++boolsAndNullsC :: Value+boolsAndNullsC = [aesonQQ| [{ "a": null }] |]++spec :: Spec+spec = do+  describe "test query" $ do+    it "returns root document when query is $" $+      queryQQ [jsonPath|$|] rootDoc `shouldBe` V.singleton rootDoc++    it "returns store object when queryQQ is $.store" $+      queryQQ [jsonPath|$.store|] rootDoc `shouldBe` V.singleton storeDoc++    it "returns store object when queryQQ is $['store']" $+      queryQQ [jsonPath|$['store']|] rootDoc `shouldBe` V.singleton storeDoc++    it "returns books array when queryQQ is $.store.books" $+      queryQQ [jsonPath|$.store.books|] rootDoc `shouldBe` V.singleton booksDoc++    it "returns 0-index book item when queryQQ is $.store.books[0]" $+      queryQQ [jsonPath|$.store.books[0]|] rootDoc `shouldBe` getVector books0Doc++    it "returns 0-index book item when queryQQ is $.store.books[-4]" $+      queryQQ [jsonPath|$.store.books[-4]|] rootDoc `shouldBe` getVector books0Doc++    it "returns 0,2-index item when queryQQ is $.store.books[0,2]" $+      queryQQ [jsonPath|$.store.books[0,2]|] rootDoc `shouldBe` getVector books0And2Doc++    it "returns 1To3-index when queryQQ is $.store.books[1:3]" $+      queryQQ [jsonPath|$.store.books[1:3]|] rootDoc `shouldBe` getVector books1To3Doc++    it "returns 1To3-index and 0,1-index when queryQQ is $.store.books[1:3,0,1]" $+      queryQQ [jsonPath|$.store.books[1:3,0,1]|] rootDoc `shouldBe` getVector books1To3And0And1Doc++    it "returns slice with queryQQ $[5:]" $+      queryQQ [jsonPath|$[5:]|] alphaArr `shouldBe` getVector fgArr++    it "returns slice with queryQQ $[1:5:2]" $+      queryQQ [jsonPath|$[1:5:2]|] alphaArr `shouldBe` getVector bdArr++    it "returns slice with queryQQ $[5:1:-2]" $+      queryQQ [jsonPath|$[5:1:-2]|] alphaArr `shouldBe` getVector fdArr++    it "returns slice with queryQQ $[::-1]" $+      queryQQ [jsonPath|$[::-1]|] alphaArr `shouldBe` getVector gfedcbaArr++    it "returns root with queryQQ $.*" $+      queryQQ [jsonPath|$.*|] rootDoc `shouldBe` V.singleton storeDoc++    it "returns root with queryQQ $[*]" $+      queryQQ [jsonPath|$[*]|] rootDoc `shouldBe` V.singleton storeDoc++    it "returns descendants with queryQQ $..*" $+      queryQQ [jsonPath|$..*|] rfcExample1 `shouldBe` getVector rfcExample1Desc++    it "returns descendants with queryQQ $..[*]" $+      queryQQ [jsonPath|$..[*]|] rfcExample1 `shouldBe` getVector rfcExample1Desc++    it "returns with filtering: number comparison" $+      queryQQ [jsonPath|$.store.books[?@.price < 20]|] rootDoc+      `shouldBe` getVector lessThanPrice20Books++    it "returns with filtering: not operator" $+      queryQQ [jsonPath|$.store.books[?!(@.price < 20)]|] rootDoc+      `shouldBe` getVector books0Doc++    it "returns with filtering: true value" $+      queryQQ [jsonPath|$[?@.a == true]|] boolsAndNulls+      `shouldBe` getVector boolsAndNullsA++    it "returns with filtering: false value" $+      queryQQ [jsonPath|$[?@.a == false]|] boolsAndNulls+      `shouldBe` getVector boolsAndNullsB++    it "returns with filtering: null value" $+      queryQQ [jsonPath|$[?@.a == null]|] boolsAndNulls+      `shouldBe` getVector boolsAndNullsC++    it "returns with filtering: string comparison" $+      queryQQ [jsonPath|$.store.books[?@.author == 'Jared Diamond']|] rootDoc+      `shouldBe` getVector books0Doc++    it "returns with filtering: test expression" $+      queryQQ [jsonPath|$.store.books[?@.author]|] rootDoc+      `shouldBe` getVector booksDoc++    it "returns with filtering with spaced out segments: test expression" $+      queryQQ [jsonPath|$  .store  .books[?@  .author]|] rootDoc+      `shouldBe` getVector booksDoc++    it "returns with filtering: test expr gives empty with non-existent key" $+      queryQQ [jsonPath|$.store.books[?@.not_here]|] rootDoc+      `shouldBe` V.empty