Make the lexer and parser safe
This commit is contained in:
parent
324a4c55ff
commit
663e4f3521
@ -11,7 +11,7 @@ author: Danny Navarro <j@dannynavarro.net>,
|
|||||||
Matthías Páll Gissurarson <mpg@mpg.is>,
|
Matthías Páll Gissurarson <mpg@mpg.is>,
|
||||||
Sólrún Halla Einarsdóttir <she@mpg.is>
|
Sólrún Halla Einarsdóttir <she@mpg.is>
|
||||||
maintainer: belka@caraus.de
|
maintainer: belka@caraus.de
|
||||||
copyright: (c) 2019-2024 Eugen Wissner,
|
copyright: (c) 2019-2025 Eugen Wissner,
|
||||||
(c) 2015-2017 J. Daniel Navarro
|
(c) 2015-2017 J. Daniel Navarro
|
||||||
license: MPL-2.0 AND BSD-3-Clause
|
license: MPL-2.0 AND BSD-3-Clause
|
||||||
license-files: LICENSE,
|
license-files: LICENSE,
|
||||||
@ -21,7 +21,7 @@ extra-source-files:
|
|||||||
CHANGELOG.md
|
CHANGELOG.md
|
||||||
README.md
|
README.md
|
||||||
tested-with:
|
tested-with:
|
||||||
GHC == 9.8.2
|
GHC == 9.10.1
|
||||||
|
|
||||||
source-repository head
|
source-repository head
|
||||||
type: git
|
type: git
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
{-# LANGUAGE NoGeneralizedNewtypeDeriving #-}
|
||||||
{-# LANGUAGE Safe #-}
|
{-# LANGUAGE Safe #-}
|
||||||
|
|
||||||
-- | Target AST for parser.
|
-- | Target AST for parser.
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
{-# LANGUAGE NoGeneralizedNewtypeDeriving #-}
|
||||||
{-# LANGUAGE Safe #-}
|
{-# LANGUAGE Safe #-}
|
||||||
|
|
||||||
-- | Various parts of a GraphQL document can be annotated with directives.
|
-- | Various parts of a GraphQL document can be annotated with directives.
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
{-# LANGUAGE NamedFieldPuns #-}
|
{-# LANGUAGE NamedFieldPuns #-}
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
{-# LANGUAGE RecordWildCards #-}
|
{-# LANGUAGE RecordWildCards #-}
|
||||||
|
{-# LANGUAGE NoGeneralizedNewtypeDeriving #-}
|
||||||
{-# LANGUAGE Safe #-}
|
{-# LANGUAGE Safe #-}
|
||||||
|
|
||||||
-- | This module defines an abstract syntax tree for the @GraphQL@ language. It
|
-- | This module defines an abstract syntax tree for the @GraphQL@ language. It
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
{-# LANGUAGE LambdaCase #-}
|
{-# LANGUAGE LambdaCase #-}
|
||||||
{-# LANGUAGE RecordWildCards #-}
|
{-# LANGUAGE RecordWildCards #-}
|
||||||
|
{-# LANGUAGE NoGeneralizedNewtypeDeriving #-}
|
||||||
{-# LANGUAGE Safe #-}
|
{-# LANGUAGE Safe #-}
|
||||||
|
|
||||||
-- | This module defines a minifier and a printer for the @GraphQL@ language.
|
-- | This module defines a minifier and a printer for the @GraphQL@ language.
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
{-# LANGUAGE ExplicitForAll #-}
|
{-# LANGUAGE ExplicitForAll #-}
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
{-# LANGUAGE NoGeneralizedNewtypeDeriving #-}
|
||||||
|
{-# LANGUAGE Safe #-}
|
||||||
|
|
||||||
-- | This module defines a bunch of small parsers used to parse individual
|
-- | This module defines a bunch of small parsers used to parse individual
|
||||||
-- lexemes.
|
-- lexemes.
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
{-# LANGUAGE LambdaCase #-}
|
{-# LANGUAGE LambdaCase #-}
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
{-# LANGUAGE RecordWildCards #-}
|
{-# LANGUAGE RecordWildCards #-}
|
||||||
|
{-# LANGUAGE NoGeneralizedNewtypeDeriving #-}
|
||||||
|
{-# LANGUAGE Safe #-}
|
||||||
|
|
||||||
-- | @GraphQL@ document parser.
|
-- | @GraphQL@ document parser.
|
||||||
module Language.GraphQL.AST.Parser
|
module Language.GraphQL.AST.Parser
|
||||||
|
@ -189,6 +189,8 @@ data QueryError
|
|||||||
| CoercionError Full.VariableDefinition
|
| CoercionError Full.VariableDefinition
|
||||||
| UnknownInputType Full.VariableDefinition
|
| UnknownInputType Full.VariableDefinition
|
||||||
|
|
||||||
|
type ExecuteHandler m a e = e -> ExecutorT m a
|
||||||
|
|
||||||
tell :: Monad m => Seq Error -> ExecutorT m ()
|
tell :: Monad m => Seq Error -> ExecutorT m ()
|
||||||
tell = ExecutorT . lift . Writer.tell
|
tell = ExecutorT . lift . Writer.tell
|
||||||
|
|
||||||
@ -313,8 +315,7 @@ executeQuery topSelections schema = do
|
|||||||
pure $ Response data' errors
|
pure $ Response data' errors
|
||||||
|
|
||||||
handleException :: (MonadCatch m, Serialize a)
|
handleException :: (MonadCatch m, Serialize a)
|
||||||
=> FieldException
|
=> ExecuteHandler m a FieldException
|
||||||
-> ExecutorT m a
|
|
||||||
handleException (FieldException fieldLocation errorPath next) =
|
handleException (FieldException fieldLocation errorPath next) =
|
||||||
let newError = constructError next fieldLocation errorPath
|
let newError = constructError next fieldLocation errorPath
|
||||||
in tell (Seq.singleton newError) >> pure null
|
in tell (Seq.singleton newError) >> pure null
|
||||||
@ -390,30 +391,28 @@ executeField objectValue fields (viewResolver -> resolverPair) errorPath =
|
|||||||
fieldErrorPath = fieldsSegment fields : errorPath
|
fieldErrorPath = fieldsSegment fields : errorPath
|
||||||
inputCoercionHandler :: (MonadCatch m, Serialize a)
|
inputCoercionHandler :: (MonadCatch m, Serialize a)
|
||||||
=> Full.Location
|
=> Full.Location
|
||||||
-> InputCoercionException
|
-> ExecuteHandler m a InputCoercionException
|
||||||
-> ExecutorT m a
|
|
||||||
inputCoercionHandler _ e@(InputCoercionException _ _ (Just valueNode)) =
|
inputCoercionHandler _ e@(InputCoercionException _ _ (Just valueNode)) =
|
||||||
let argumentLocation = getField @"location" valueNode
|
let argumentLocation = getField @"location" valueNode
|
||||||
in exceptionHandler argumentLocation e
|
in exceptionHandler argumentLocation e
|
||||||
inputCoercionHandler fieldLocation e = exceptionHandler fieldLocation e
|
inputCoercionHandler fieldLocation e = exceptionHandler fieldLocation e
|
||||||
resultHandler :: (MonadCatch m, Serialize a)
|
resultHandler :: (MonadCatch m, Serialize a)
|
||||||
=> Full.Location
|
=> Full.Location
|
||||||
-> ResultException
|
-> ExecuteHandler m a ResultException
|
||||||
-> ExecutorT m a
|
|
||||||
resultHandler = exceptionHandler
|
resultHandler = exceptionHandler
|
||||||
resolverHandler :: (MonadCatch m, Serialize a)
|
resolverHandler :: (MonadCatch m, Serialize a)
|
||||||
=> Full.Location
|
=> Full.Location
|
||||||
-> ResolverException
|
-> ExecuteHandler m a ResolverException
|
||||||
-> ExecutorT m a
|
|
||||||
resolverHandler = exceptionHandler
|
resolverHandler = exceptionHandler
|
||||||
nullResultHandler :: (MonadCatch m, Serialize a)
|
nullResultHandler :: (MonadCatch m, Serialize a) => ExecuteHandler m a FieldException
|
||||||
=> FieldException
|
|
||||||
-> ExecutorT m a
|
|
||||||
nullResultHandler e@(FieldException fieldLocation errorPath' next) =
|
nullResultHandler e@(FieldException fieldLocation errorPath' next) =
|
||||||
let newError = constructError next fieldLocation errorPath'
|
let newError = constructError next fieldLocation errorPath'
|
||||||
in if Out.isNonNullType fieldType
|
in if Out.isNonNullType fieldType
|
||||||
then throwM e
|
then throwM e
|
||||||
else returnError newError
|
else returnError newError
|
||||||
|
exceptionHandler :: (Exception e, MonadCatch m, Serialize a)
|
||||||
|
=> Full.Location
|
||||||
|
-> ExecuteHandler m a e
|
||||||
exceptionHandler errorLocation e =
|
exceptionHandler errorLocation e =
|
||||||
let newError = constructError e errorLocation fieldErrorPath
|
let newError = constructError e errorLocation fieldErrorPath
|
||||||
in if Out.isNonNullType fieldType
|
in if Out.isNonNullType fieldType
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
obtain one at https://mozilla.org/MPL/2.0/. -}
|
obtain one at https://mozilla.org/MPL/2.0/. -}
|
||||||
|
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
{-# LANGUAGE NoGeneralizedNewtypeDeriving #-}
|
||||||
{-# LANGUAGE Safe #-}
|
{-# LANGUAGE Safe #-}
|
||||||
|
|
||||||
-- | Types that can be used as both input and output types.
|
-- | Types that can be used as both input and output types.
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
obtain one at https://mozilla.org/MPL/2.0/. -}
|
obtain one at https://mozilla.org/MPL/2.0/. -}
|
||||||
|
|
||||||
{-# LANGUAGE PatternSynonyms #-}
|
{-# LANGUAGE PatternSynonyms #-}
|
||||||
|
{-# LANGUAGE NoGeneralizedNewtypeDeriving #-}
|
||||||
{-# LANGUAGE Safe #-}
|
{-# LANGUAGE Safe #-}
|
||||||
{-# LANGUAGE ViewPatterns #-}
|
{-# LANGUAGE ViewPatterns #-}
|
||||||
|
|
||||||
|
@ -1067,18 +1067,12 @@ overlappingFieldsCanBeMergedRule = OperationDefinitionRule $ \case
|
|||||||
go selectionSet selectionType = do
|
go selectionSet selectionType = do
|
||||||
fieldTuples <- evalStateT (collectFields selectionType selectionSet) HashSet.empty
|
fieldTuples <- evalStateT (collectFields selectionType selectionSet) HashSet.empty
|
||||||
fieldsInSetCanMerge fieldTuples
|
fieldsInSetCanMerge fieldTuples
|
||||||
fieldsInSetCanMerge :: forall m
|
|
||||||
. HashMap Full.Name (NonEmpty (Full.Field, Type.CompositeType m))
|
|
||||||
-> ReaderT (Validation m) Seq Error
|
|
||||||
fieldsInSetCanMerge fieldTuples = do
|
fieldsInSetCanMerge fieldTuples = do
|
||||||
validation <- ask
|
validation <- ask
|
||||||
let (lonely, paired) = flattenPairs fieldTuples
|
let (lonely, paired) = flattenPairs fieldTuples
|
||||||
let reader = flip runReaderT validation
|
let reader = flip runReaderT validation
|
||||||
lift $ foldMap (reader . visitLonelyFields) lonely
|
lift $ foldMap (reader . visitLonelyFields) lonely
|
||||||
<> foldMap (reader . forEachFieldTuple) paired
|
<> foldMap (reader . forEachFieldTuple) paired
|
||||||
forEachFieldTuple :: forall m
|
|
||||||
. (FieldInfo m, FieldInfo m)
|
|
||||||
-> ReaderT (Validation m) Seq Error
|
|
||||||
forEachFieldTuple (fieldA, fieldB) =
|
forEachFieldTuple (fieldA, fieldB) =
|
||||||
case (parent fieldA, parent fieldB) of
|
case (parent fieldA, parent fieldB) of
|
||||||
(parentA@Type.CompositeObjectType{}, parentB@Type.CompositeObjectType{})
|
(parentA@Type.CompositeObjectType{}, parentB@Type.CompositeObjectType{})
|
||||||
@ -1105,10 +1099,6 @@ overlappingFieldsCanBeMergedRule = OperationDefinitionRule $ \case
|
|||||||
let Full.Field _ _ _ _ subSelections _ = node
|
let Full.Field _ _ _ _ subSelections _ = node
|
||||||
compositeFieldType = Type.outToComposite type'
|
compositeFieldType = Type.outToComposite type'
|
||||||
in maybe (lift Seq.empty) (go subSelections) compositeFieldType
|
in maybe (lift Seq.empty) (go subSelections) compositeFieldType
|
||||||
sameResponseShape :: forall m
|
|
||||||
. FieldInfo m
|
|
||||||
-> FieldInfo m
|
|
||||||
-> ReaderT (Validation m) Seq Error
|
|
||||||
sameResponseShape fieldA fieldB =
|
sameResponseShape fieldA fieldB =
|
||||||
let Full.Field _ _ _ _ selectionsA _ = node fieldA
|
let Full.Field _ _ _ _ selectionsA _ = node fieldA
|
||||||
Full.Field _ _ _ _ selectionsB _ = node fieldB
|
Full.Field _ _ _ _ selectionsB _ = node fieldB
|
||||||
|
Loading…
x
Reference in New Issue
Block a user