Skip to content

Commit

Permalink
fix: handle escape characters in normalized path properly (#57)
Browse files Browse the repository at this point in the history
  • Loading branch information
taimoorzaeem authored Feb 19, 2025
1 parent 42532c1 commit ff22ff1
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 9 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ All notable changes to this package are documented in this file. This project ad

## Unreleased

- #50, Fix wrong normalized path with descendant segment
- #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

Expand Down
16 changes: 15 additions & 1 deletion src/Data/Aeson/JSONPath/Query/Segment.hs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,21 @@ allElemsRecursiveLocated (loc, a@(JSON.Array arr)) = V.concat [
allElemsRecursiveLocated _ = V.empty

toPathKey :: String -> KM.Key -> String
toPathKey loc key = loc ++ "['" ++ K.toString key ++ "']"
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 ++ "]"
16 changes: 15 additions & 1 deletion src/Data/Aeson/JSONPath/Query/Selector.hs
Original file line number Diff line number Diff line change
Expand Up @@ -122,4 +122,18 @@ sliceArrayLocated (start,end,step) vec =


toPathKey :: String -> Text -> String
toPathKey loc key = loc ++ "['" ++ T.unpack key ++ "']"
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]
12 changes: 6 additions & 6 deletions test/compliance/ComplianceSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import qualified Text.ParserCombinators.Parsec as P

import Control.Monad (mzero)
import Data.Aeson ((.:),(.:?),Value)
import Data.Aeson.JSONPath (query)
import Data.Aeson.JSONPath (query, queryLocated)
import Data.Aeson.JSONPath.Parser (pQuery)
import Data.Either (isLeft, fromRight)
import Data.Vector (Vector)
Expand Down Expand Up @@ -77,17 +77,17 @@ runTestCase TestCase{invalidSel=(Just True), ..} =
P.parse pQuery "" selector `shouldSatisfy` isLeft

-- if result is deterministic (one json)
runTestCase TestCase{result=(Just r), {-resultPaths=(Just rp),-} document=(Just doc), ..} =
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)
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
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)
queryLocated selector doc `shouldSatisfy` (\x -> fromRight V.empty x `elem` vecList)
where
-- vecList = [ V.zip rp r | rp <- rsp, r <- rs]
vecList = [ V.zip rp r | rp <- rsp, r <- rs]

runTestCase _ = pure ()

0 comments on commit ff22ff1

Please sign in to comment.