0
# Language Processing and AST
1
2
Parse GraphQL documents into Abstract Syntax Trees (AST), manipulate AST nodes, and work with GraphQL source code. This module provides lexical analysis, parsing capabilities, and visitor patterns for AST traversal and manipulation.
3
4
## Capabilities
5
6
### Document Parsing
7
8
Parse GraphQL documents, values, and types from string sources into structured AST representations.
9
10
```python { .api }
11
def parse(source: Union[str, Source]) -> DocumentNode
12
def parse_value(source: Union[str, Source]) -> ValueNode
13
def parse_const_value(source: Union[str, Source]) -> ConstValueNode
14
def parse_type(source: Union[str, Source]) -> TypeNode
15
```
16
17
**Parameters:**
18
- `source`: GraphQL source string or Source object to parse
19
20
**Returns:** Corresponding AST node type
21
22
#### Usage Examples
23
24
```python
25
from graphql import parse, parse_value, parse_type
26
27
# Parse a complete GraphQL document
28
query = '''
29
query GetUser($id: ID!) {
30
user(id: $id) {
31
name
32
33
}
34
}
35
'''
36
document = parse(query)
37
print(document.kind) # 'document'
38
print(len(document.definitions)) # 1
39
40
# Parse individual values
41
value_ast = parse_value('"hello world"')
42
print(value_ast.kind) # 'string_value'
43
print(value_ast.value) # 'hello world'
44
45
# Parse type expressions
46
type_ast = parse_type('[String!]!')
47
print(type_ast.kind) # 'non_null_type'
48
```
49
50
### Source Handling
51
52
Manage GraphQL source code with location tracking for enhanced error reporting and tooling.
53
54
```python { .api }
55
class Source:
56
def __init__(self, body: str, name: str = "GraphQL request", location_offset: SourceLocation = None)
57
58
body: str
59
name: str
60
location_offset: SourceLocation
61
62
def get_location(source: Source, position: int) -> SourceLocation
63
64
class SourceLocation:
65
line: int
66
column: int
67
```
68
69
#### Usage Example
70
71
```python
72
from graphql import Source, get_location, parse
73
74
source = Source('''
75
query {
76
user {
77
name
78
}
79
}
80
''', name="user-query.graphql")
81
82
# Parse with source tracking
83
document = parse(source)
84
85
# Get location information
86
location = get_location(source, 20)
87
print(f"Line {location.line}, Column {location.column}")
88
```
89
90
### Lexical Analysis
91
92
Tokenize GraphQL source code for custom parsing or analysis tools.
93
94
```python { .api }
95
class Lexer:
96
def __init__(self, source: Source)
97
98
def next_token(self) -> Token
99
def lookahead(self) -> Token
100
101
class Token:
102
kind: TokenKind
103
start: int
104
end: int
105
line: int
106
column: int
107
value: Optional[str]
108
prev: Optional[Token]
109
next: Optional[Token]
110
111
class TokenKind(Enum):
112
SOF = "StartOfFile"
113
EOF = "EndOfFile"
114
BANG = "!"
115
DOLLAR = "$"
116
AMP = "&"
117
PAREN_L = "("
118
PAREN_R = ")"
119
SPREAD = "..."
120
COLON = ":"
121
EQUALS = "="
122
AT = "@"
123
BRACKET_L = "["
124
BRACKET_R = "]"
125
BRACE_L = "{"
126
PIPE = "|"
127
BRACE_R = "}"
128
NAME = "Name"
129
INT = "Int"
130
FLOAT = "Float"
131
STRING = "String"
132
BLOCK_STRING = "BlockString"
133
COMMENT = "Comment"
134
```
135
136
#### Usage Example
137
138
```python
139
from graphql import Source, Lexer, TokenKind
140
141
source = Source('{ hello world }')
142
lexer = Lexer(source)
143
144
token = lexer.next_token()
145
while token.kind != TokenKind.EOF:
146
print(f"{token.kind.value}: {token.value}")
147
token = lexer.next_token()
148
```
149
150
### AST Printing
151
152
Convert AST nodes back to GraphQL string representation.
153
154
```python { .api }
155
def print_ast(ast: Node) -> str
156
```
157
158
#### Usage Example
159
160
```python
161
from graphql import parse, print_ast
162
163
document = parse('{ user { name email } }')
164
printed = print_ast(document)
165
print(printed) # Formatted GraphQL string
166
```
167
168
### AST Traversal and Manipulation
169
170
Visit and transform AST nodes using the visitor pattern.
171
172
```python { .api }
173
def visit(root: Node, visitor: Visitor, visitor_keys: Optional[VisitorKeyMap] = None) -> Any
174
175
class Visitor:
176
def enter(self, node: Node, key: Optional[str], parent: Optional[Node], path: List[Union[int, str]], ancestors: List[Node]) -> Optional[VisitorAction]
177
def leave(self, node: Node, key: Optional[str], parent: Optional[Node], path: List[Union[int, str]], ancestors: List[Node]) -> Optional[Union[VisitorAction, Node]]
178
179
class ParallelVisitor:
180
def __init__(self, visitors: Sequence[Visitor])
181
182
class VisitorAction(Enum):
183
BREAK = object()
184
SKIP = object()
185
REMOVE = object()
186
IDLE = object()
187
188
# Visitor action constants
189
BREAK: VisitorAction
190
SKIP: VisitorAction
191
REMOVE: VisitorAction
192
IDLE: VisitorAction
193
```
194
195
#### Usage Example
196
197
```python
198
from graphql import parse, visit, Visitor
199
200
class FieldNameCollector(Visitor):
201
def __init__(self):
202
self.field_names = []
203
204
def enter(self, node, key, parent, path, ancestors):
205
if node.kind == 'field':
206
self.field_names.append(node.name.value)
207
208
document = parse('{ user { name email posts { title } } }')
209
collector = FieldNameCollector()
210
visit(document, collector)
211
print(collector.field_names) # ['user', 'name', 'email', 'posts', 'title']
212
```
213
214
### Location and Error Reporting
215
216
Print formatted location information for debugging and error reporting.
217
218
```python { .api }
219
def print_location(location: Location) -> str
220
def print_source_location(source: Source, location: SourceLocation) -> str
221
222
class Location:
223
start: int
224
end: int
225
start_token: Token
226
end_token: Token
227
source: Source
228
```
229
230
## AST Node Types
231
232
### Base Node Types
233
234
```python { .api }
235
class Node:
236
kind: str
237
loc: Optional[Location]
238
239
class NameNode(Node):
240
kind: str = 'name'
241
value: str
242
243
class DocumentNode(Node):
244
kind: str = 'document'
245
definitions: List[DefinitionNode]
246
```
247
248
### Definition Nodes
249
250
```python { .api }
251
class DefinitionNode(Node):
252
pass
253
254
class ExecutableDefinitionNode(DefinitionNode):
255
pass
256
257
class OperationDefinitionNode(ExecutableDefinitionNode):
258
kind: str = 'operation_definition'
259
operation: OperationType
260
name: Optional[NameNode]
261
variable_definitions: Optional[List[VariableDefinitionNode]]
262
directives: Optional[List[DirectiveNode]]
263
selection_set: SelectionSetNode
264
265
class OperationType(Enum):
266
QUERY = 'query'
267
MUTATION = 'mutation'
268
SUBSCRIPTION = 'subscription'
269
270
class FragmentDefinitionNode(ExecutableDefinitionNode):
271
kind: str = 'fragment_definition'
272
name: NameNode
273
variable_definitions: Optional[List[VariableDefinitionNode]]
274
type_condition: NamedTypeNode
275
directives: Optional[List[DirectiveNode]]
276
selection_set: SelectionSetNode
277
```
278
279
### Selection Nodes
280
281
```python { .api }
282
class SelectionNode(Node):
283
pass
284
285
class FieldNode(SelectionNode):
286
kind: str = 'field'
287
alias: Optional[NameNode]
288
name: NameNode
289
arguments: Optional[List[ArgumentNode]]
290
directives: Optional[List[DirectiveNode]]
291
selection_set: Optional[SelectionSetNode]
292
293
class SelectionSetNode(Node):
294
kind: str = 'selection_set'
295
selections: List[SelectionNode]
296
297
class FragmentSpreadNode(SelectionNode):
298
kind: str = 'fragment_spread'
299
name: NameNode
300
directives: Optional[List[DirectiveNode]]
301
302
class InlineFragmentNode(SelectionNode):
303
kind: str = 'inline_fragment'
304
type_condition: Optional[NamedTypeNode]
305
directives: Optional[List[DirectiveNode]]
306
selection_set: SelectionSetNode
307
```
308
309
### Value Nodes
310
311
```python { .api }
312
class ValueNode(Node):
313
pass
314
315
class ConstValueNode(ValueNode):
316
pass
317
318
class VariableNode(ValueNode):
319
kind: str = 'variable'
320
name: NameNode
321
322
class IntValueNode(ConstValueNode):
323
kind: str = 'int_value'
324
value: str
325
326
class FloatValueNode(ConstValueNode):
327
kind: str = 'float_value'
328
value: str
329
330
class StringValueNode(ConstValueNode):
331
kind: str = 'string_value'
332
value: str
333
block: bool
334
335
class BooleanValueNode(ConstValueNode):
336
kind: str = 'boolean_value'
337
value: bool
338
339
class NullValueNode(ConstValueNode):
340
kind: str = 'null_value'
341
342
class EnumValueNode(ConstValueNode):
343
kind: str = 'enum_value'
344
value: str
345
346
class ListValueNode(ValueNode):
347
kind: str = 'list_value'
348
values: List[ValueNode]
349
350
class ObjectValueNode(ValueNode):
351
kind: str = 'object_value'
352
fields: List[ObjectFieldNode]
353
354
class ObjectFieldNode(Node):
355
kind: str = 'object_field'
356
name: NameNode
357
value: ValueNode
358
```
359
360
### Type Nodes
361
362
```python { .api }
363
class TypeNode(Node):
364
pass
365
366
class NamedTypeNode(TypeNode):
367
kind: str = 'named_type'
368
name: NameNode
369
370
class ListTypeNode(TypeNode):
371
kind: str = 'list_type'
372
type: TypeNode
373
374
class NonNullTypeNode(TypeNode):
375
kind: str = 'non_null_type'
376
type: Union[NamedTypeNode, ListTypeNode]
377
```
378
379
### Predicate Functions
380
381
```python { .api }
382
def is_definition_node(node: Node) -> bool
383
def is_executable_definition_node(node: Node) -> bool
384
def is_selection_node(node: Node) -> bool
385
def is_value_node(node: Node) -> bool
386
def is_const_value_node(node: Node) -> bool
387
def is_type_node(node: Node) -> bool
388
def is_type_system_definition_node(node: Node) -> bool
389
def is_type_definition_node(node: Node) -> bool
390
def is_type_system_extension_node(node: Node) -> bool
391
def is_type_extension_node(node: Node) -> bool
392
```