graphql-engine/server/src-lib/Data/Parser/JSONPath.hs
Robert 11a454c2d6 server, pro: actually reformat the code-base using ormolu
This commit applies ormolu to the whole Haskell code base by running `make format`.

For in-flight branches, simply merging changes from `main` will result in merge conflicts.
To avoid this, update your branch using the following instructions. Replace `<format-commit>`
by the hash of *this* commit.

$ git checkout my-feature-branch
$ git merge <format-commit>^    # and resolve conflicts normally
$ make format
$ git commit -a -m "reformat with ormolu"
$ git merge -s ours post-ormolu

https://github.com/hasura/graphql-engine-mono/pull/2404

GitOrigin-RevId: 75049f5c12f430c615eafb4c6b8e83e371e01c8e
2021-09-23 22:57:37 +00:00

64 lines
1.8 KiB
Haskell

module Data.Parser.JSONPath
( parseJSONPath,
JSONPathElement (..),
JSONPath,
)
where
import Control.Applicative
import Control.Monad (void)
import Data.Aeson.Internal (JSONPath, JSONPathElement (..))
import Data.Attoparsec.Text
import Data.Bifunctor
import Data.Text qualified as T
import Prelude
parseJSONPath :: T.Text -> Either String JSONPath
parseJSONPath "$" = Right []
parseJSONPath txt =
first (const invalidMessage) $
parseOnly (optional (char '$') *> many1' element <* endOfInput) txt
where
invalidMessage =
T.unpack txt
++ ". Accept letters, digits, underscore (_) or hyphen (-) only"
++ ". Use single quotes enclosed in bracket (['...']) if there is any special character"
element :: Parser JSONPathElement
element =
Key <$> (optional (char '.') *> name) -- field or .field
<|> bracketElement -- [42] or ['field']
name :: Parser T.Text
name = go <?> "property name"
where
go = do
firstChar <-
letter
<|> char '_'
<?> "first character of property name must be a letter or underscore"
otherChars <- many' (letter <|> digit <|> satisfy (inClass "-_"))
pure $ T.pack (firstChar : otherChars)
-- | Parses a JSON property key or index in square bracket format, e.g.
-- > [42]
-- > ["hello"]
-- > ['你好']
bracketElement :: Parser JSONPathElement
bracketElement = do
void $ optional (char '.') *> char '['
result <-
Index <$> decimal
<|> Key <$> quotedString '"'
<|> Key <$> quotedString '\''
void $ char ']'
pure result
where
quotedString delimiter = do
void $ char delimiter
result <- T.pack <$> many' (charOrEscape delimiter)
void $ char delimiter
pure result
charOrEscape delimiter = (char '\\' *> anyChar) <|> notChar delimiter