1717 DirectiveArgumentCoordinateNode ,
1818 DirectiveCoordinateNode ,
1919 DirectiveDefinitionNode ,
20+ DirectiveExtensionNode ,
2021 DirectiveNode ,
2122 DocumentNode ,
2223 EnumTypeDefinitionNode ,
@@ -96,6 +97,7 @@ def parse(
9697 no_location : bool = False ,
9798 max_tokens : int | None = None ,
9899 experimental_fragment_arguments : bool = False ,
100+ experimental_directives_on_directive_definitions : bool = False ,
99101) -> DocumentNode :
100102 """Given a GraphQL source, parse it into a Document.
101103
@@ -130,12 +132,23 @@ def parse(
130132 fragment A($var: Boolean = false) on T {
131133 ...B(x: $var)
132134 }
135+
136+ Experimental feature:
137+
138+ If ``experimental_directives_on_directive_definitions`` is set to ``True``, the
139+ parser will understand and parse directives on directive definitions. This syntax
140+ is not part of the GraphQL specification and may change. For example::
141+
142+ directive @foo @bar on FIELD
133143 """
134144 parser = Parser (
135145 source ,
136146 no_location = no_location ,
137147 max_tokens = max_tokens ,
138148 experimental_fragment_arguments = experimental_fragment_arguments ,
149+ experimental_directives_on_directive_definitions = (
150+ experimental_directives_on_directive_definitions
151+ ),
139152 )
140153 return parser .parse_document ()
141154
@@ -145,6 +158,7 @@ def parse_value(
145158 no_location : bool = False ,
146159 max_tokens : int | None = None ,
147160 experimental_fragment_arguments : bool = False ,
161+ experimental_directives_on_directive_definitions : bool = False ,
148162) -> ValueNode :
149163 """Parse the AST for a given string containing a GraphQL value.
150164
@@ -158,6 +172,9 @@ def parse_value(
158172 no_location = no_location ,
159173 max_tokens = max_tokens ,
160174 experimental_fragment_arguments = experimental_fragment_arguments ,
175+ experimental_directives_on_directive_definitions = (
176+ experimental_directives_on_directive_definitions
177+ ),
161178 )
162179 parser .expect_token (TokenKind .SOF )
163180 value = parser .parse_value_literal (False )
@@ -170,6 +187,7 @@ def parse_const_value(
170187 no_location : bool = False ,
171188 max_tokens : int | None = None ,
172189 experimental_fragment_arguments : bool = False ,
190+ experimental_directives_on_directive_definitions : bool = False ,
173191) -> ConstValueNode :
174192 """Parse the AST for a given string containing a GraphQL constant value.
175193
@@ -181,6 +199,9 @@ def parse_const_value(
181199 no_location = no_location ,
182200 max_tokens = max_tokens ,
183201 experimental_fragment_arguments = experimental_fragment_arguments ,
202+ experimental_directives_on_directive_definitions = (
203+ experimental_directives_on_directive_definitions
204+ ),
184205 )
185206 parser .expect_token (TokenKind .SOF )
186207 value = parser .parse_const_value_literal ()
@@ -193,6 +214,7 @@ def parse_type(
193214 no_location : bool = False ,
194215 max_tokens : int | None = None ,
195216 experimental_fragment_arguments : bool = False ,
217+ experimental_directives_on_directive_definitions : bool = False ,
196218) -> TypeNode :
197219 """Parse the AST for a given string containing a GraphQL Type.
198220
@@ -209,6 +231,9 @@ def parse_type(
209231 no_location = no_location ,
210232 max_tokens = max_tokens ,
211233 experimental_fragment_arguments = experimental_fragment_arguments ,
234+ experimental_directives_on_directive_definitions = (
235+ experimental_directives_on_directive_definitions
236+ ),
212237 )
213238 parser .expect_token (TokenKind .SOF )
214239 type_ = parser .parse_type_reference ()
@@ -258,6 +283,7 @@ class Parser:
258283 _no_location : bool
259284 _max_tokens : int | None
260285 _experimental_fragment_arguments : bool
286+ _experimental_directives_on_directive_definitions : bool
261287 _lexer : Lexer
262288 _token_counter : int
263289
@@ -267,6 +293,7 @@ def __init__(
267293 no_location : bool = False ,
268294 max_tokens : int | None = None ,
269295 experimental_fragment_arguments : bool = False ,
296+ experimental_directives_on_directive_definitions : bool = False ,
270297 lexer : Lexer | None = None ,
271298 ) -> None :
272299 if not is_source (source ):
@@ -275,6 +302,9 @@ def __init__(
275302 self ._no_location = no_location
276303 self ._max_tokens = max_tokens
277304 self ._experimental_fragment_arguments = experimental_fragment_arguments
305+ self ._experimental_directives_on_directive_definitions = (
306+ experimental_directives_on_directive_definitions
307+ )
278308 # You may override the lexer used to lex the source; this is used by schema
279309 # coordinates to introduce a lexer with a restricted syntax.
280310 self ._lexer = lexer if lexer is not None else Lexer (source )
@@ -754,6 +784,11 @@ def parse_type_system_extension(self) -> TypeSystemExtensionNode:
754784 )
755785 if method_name : # pragma: no cover
756786 return getattr (self , f"parse_{ method_name } " )()
787+ if (
788+ keyword_token .value == "directive"
789+ and self ._experimental_directives_on_directive_definitions
790+ ):
791+ return self .parse_directive_definition_extension ()
757792 raise self .unexpected (keyword_token )
758793
759794 def peek_description (self ) -> bool :
@@ -1105,6 +1140,22 @@ def parse_input_object_type_extension(self) -> InputObjectTypeExtensionNode:
11051140 name = name , directives = directives , fields = fields , loc = self .loc (start )
11061141 )
11071142
1143+ def parse_directive_definition_extension (self ) -> DirectiveExtensionNode :
1144+ """DirectiveDefinitionExtension"""
1145+ start = self ._lexer .token
1146+ self .expect_keyword ("extend" )
1147+ self .expect_keyword ("directive" )
1148+ self .expect_token (TokenKind .AT )
1149+ name = self .parse_name ()
1150+ directives = self .parse_const_directives ()
1151+ if not directives :
1152+ raise self .unexpected ()
1153+ return DirectiveExtensionNode (
1154+ name = name ,
1155+ directives = directives ,
1156+ loc = self .loc (start ),
1157+ )
1158+
11081159 def parse_directive_definition (self ) -> DirectiveDefinitionNode :
11091160 """DirectiveDefinition"""
11101161 start = self ._lexer .token
@@ -1113,13 +1164,19 @@ def parse_directive_definition(self) -> DirectiveDefinitionNode:
11131164 self .expect_token (TokenKind .AT )
11141165 name = self .parse_name ()
11151166 args = self .parse_argument_defs ()
1167+ directives = (
1168+ self .parse_const_directives ()
1169+ if self ._experimental_directives_on_directive_definitions
1170+ else None
1171+ )
11161172 repeatable = self .expect_optional_keyword ("repeatable" )
11171173 self .expect_keyword ("on" )
11181174 locations = self .parse_directive_locations ()
11191175 return DirectiveDefinitionNode (
11201176 description = description ,
11211177 name = name ,
11221178 arguments = args ,
1179+ directives = directives ,
11231180 repeatable = repeatable ,
11241181 locations = locations ,
11251182 loc = self .loc (start ),
0 commit comments