apollo_compiler/ast/mod.rs
1//! *Abstract Syntax Tree* for GraphQL documents.
2//! An AST [`Document`] is more permissive but lower-level than [`Schema`][crate::Schema]
3//! or [`ExecutableDocument`][crate::ExecutableDocument].
4//!
5//! This AST aims to faithfully represent documents
6//! that conform to the GraphQL [syntactic grammar],
7//! except that [ignored tokens] such as whitespace are not preserved.
8//! These documents may or may not be [valid].
9//!
10//! Parsing an input that does not conform to the grammar results in parse errors
11//! together with a partial AST.
12//!
13//! [ignored tokens]: https://spec.graphql.org/September2025/#Ignored
14//! [syntactic grammar]: https://spec.graphql.org/September2025/#sec-Language
15//! [valid]: https://spec.graphql.org/September2025/#sec-Validation
16//!
17//! ## Parsing
18//!
19//! Start with [`Document::parse`], or [`Parser`][crate::parser::Parser]
20//! to change the parser configuration.
21//!
22//! ## Structural sharing and mutation
23//!
24//! Nodes inside documents are wrapped in [`Node`], a reference-counted smart pointer.
25//! This allows sharing nodes between documents without cloning entire subtrees.
26//! To modify a node, the [`make_mut`][Node::make_mut] method provides copy-on-write semantics.
27//!
28//! ## Serialization
29//!
30//! [`Document`] and its node types implement [`Display`][std::fmt::Display]
31//! and [`ToString`] by serializing to GraphQL syntax with a default configuration.
32//! [`serialize`][Document::serialize] methods return a builder
33//! that has chaining methods for setting serialization configuration,
34//! and also implements `Display` and `ToString`.
35//!
36//! ## Example
37//!
38//! ```
39//! use apollo_compiler::{ast, name};
40//!
41//! let source = "{field}";
42//! let mut doc = ast::Document::parse(source, "example.graphql").unwrap();
43//! for def in &mut doc.definitions {
44//! if let ast::Definition::OperationDefinition(op) = def {
45//! // `op` has type `&mut Node<ast::OperationDefinition>`
46//! // `Node` implements `Deref` but not `DeferMut`
47//! // `make_mut()` clones if necessary and returns `&mut ast::OperationDefinition`
48//! op.make_mut().directives.push(ast::Directive::new(name!(dir)));
49//! }
50//! }
51//! assert_eq!(doc.serialize().no_indent().to_string(), "query @dir { field }")
52//! ```
53
54use crate::parser::SourceMap;
55use crate::Name;
56use crate::Node;
57
58pub(crate) mod from_cst;
59pub(crate) mod impls;
60pub(crate) mod serialize;
61
62pub use self::serialize::Serialize;
63
64/// AST for a GraphQL [_Document_](https://spec.graphql.org/September2025/#Document)
65/// that can contain executable definitions, type system (schema) definitions, or both.
66///
67/// It is typically parsed from one `&str` input “file” but can be also be synthesized
68/// programatically.
69#[derive(Clone)]
70pub struct Document {
71 /// If this document was originally parsed from a source file,
72 /// this map contains one entry for that file and its ID.
73 ///
74 /// The document is [mutable][crate::ast#structural-sharing-and-mutation]
75 /// so it may have been modified since.
76 pub sources: SourceMap,
77
78 pub definitions: Vec<Definition>,
79}
80
81const _: () = {
82 const fn assert_send<T: Send>() {}
83 const fn assert_sync<T: Sync>() {}
84 assert_send::<Document>();
85 assert_sync::<Document>();
86};
87
88/// A [_NamedType_](https://spec.graphql.org/September2025/#NamedType)
89/// references by name a GraphQL type defined elsewhere.
90pub type NamedType = Name;
91
92/// AST for a top-level [_Definition_](https://spec.graphql.org/September2025/#Definition) of any kind:
93/// executable, type system, or type system extension.
94#[derive(Clone, Eq, PartialEq, Hash)]
95pub enum Definition {
96 OperationDefinition(Node<OperationDefinition>),
97 FragmentDefinition(Node<FragmentDefinition>),
98 DirectiveDefinition(Node<DirectiveDefinition>),
99 SchemaDefinition(Node<SchemaDefinition>),
100 ScalarTypeDefinition(Node<ScalarTypeDefinition>),
101 ObjectTypeDefinition(Node<ObjectTypeDefinition>),
102 InterfaceTypeDefinition(Node<InterfaceTypeDefinition>),
103 UnionTypeDefinition(Node<UnionTypeDefinition>),
104 EnumTypeDefinition(Node<EnumTypeDefinition>),
105 InputObjectTypeDefinition(Node<InputObjectTypeDefinition>),
106 SchemaExtension(Node<SchemaExtension>),
107 ScalarTypeExtension(Node<ScalarTypeExtension>),
108 ObjectTypeExtension(Node<ObjectTypeExtension>),
109 InterfaceTypeExtension(Node<InterfaceTypeExtension>),
110 UnionTypeExtension(Node<UnionTypeExtension>),
111 EnumTypeExtension(Node<EnumTypeExtension>),
112 InputObjectTypeExtension(Node<InputObjectTypeExtension>),
113}
114
115/// Executable AST for an
116/// [_OperationDefinition_](https://spec.graphql.org/September2025/#OperationDefinition).
117#[derive(Clone, Debug, Eq, PartialEq, Hash)]
118pub struct OperationDefinition {
119 pub description: Option<Node<str>>,
120 pub operation_type: OperationType,
121 pub name: Option<Name>,
122 pub variables: Vec<Node<VariableDefinition>>,
123 pub directives: DirectiveList,
124 pub selection_set: Vec<Selection>,
125}
126
127/// Executable AST for a
128/// [_FragmentDefinition_](https://spec.graphql.org/September2025/#FragmentDefinition).
129#[derive(Clone, Debug, Eq, PartialEq, Hash)]
130pub struct FragmentDefinition {
131 pub description: Option<Node<str>>,
132 pub name: Name,
133 pub type_condition: NamedType,
134 pub directives: DirectiveList,
135 pub selection_set: Vec<Selection>,
136}
137
138/// Type system AST for a `directive @foo`
139/// [_DirectiveDefinition_](https://spec.graphql.org/September2025/#DirectiveDefinition).
140#[derive(Clone, Debug, Eq, PartialEq, Hash)]
141pub struct DirectiveDefinition {
142 pub description: Option<Node<str>>,
143 pub name: Name,
144 pub arguments: Vec<Node<InputValueDefinition>>,
145 pub repeatable: bool,
146 pub locations: Vec<DirectiveLocation>,
147}
148
149/// Type system AST for a `schema`
150/// [_SchemaDefinition_](https://spec.graphql.org/September2025/#SchemaDefinition).
151#[derive(Clone, Debug, Eq, PartialEq, Hash)]
152pub struct SchemaDefinition {
153 pub description: Option<Node<str>>,
154 pub directives: DirectiveList,
155 pub root_operations: Vec<Node<(OperationType, NamedType)>>,
156}
157
158/// Type system AST for a `scalar FooS`
159/// [_ScalarTypeDefinition_](https://spec.graphql.org/September2025/#ScalarTypeDefinition).
160#[derive(Clone, Debug, Eq, PartialEq, Hash)]
161pub struct ScalarTypeDefinition {
162 pub description: Option<Node<str>>,
163 pub name: Name,
164 pub directives: DirectiveList,
165}
166
167/// Type system AST for a `type FooO`
168/// [_ObjectTypeDefinition_](https://spec.graphql.org/September2025/#ObjectTypeDefinition).
169#[derive(Clone, Debug, Eq, PartialEq, Hash)]
170pub struct ObjectTypeDefinition {
171 pub description: Option<Node<str>>,
172 pub name: Name,
173 pub implements_interfaces: Vec<Name>,
174 pub directives: DirectiveList,
175 pub fields: Vec<Node<FieldDefinition>>,
176}
177
178/// Type system AST for an `interface FooI`
179/// [_InterfaceTypeDefinition_](https://spec.graphql.org/September2025/#InterfaceTypeDefinition).
180#[derive(Clone, Debug, Eq, PartialEq, Hash)]
181pub struct InterfaceTypeDefinition {
182 pub description: Option<Node<str>>,
183 pub name: Name,
184 pub implements_interfaces: Vec<Name>,
185 pub directives: DirectiveList,
186 pub fields: Vec<Node<FieldDefinition>>,
187}
188
189/// Type system AST for a `union FooU`
190/// [_UnionTypeDefinition_](https://spec.graphql.org/September2025/#UnionTypeDefinition).
191#[derive(Clone, Debug, Eq, PartialEq, Hash)]
192pub struct UnionTypeDefinition {
193 pub description: Option<Node<str>>,
194 pub name: Name,
195 pub directives: DirectiveList,
196 pub members: Vec<NamedType>,
197}
198
199/// Type system AST for an `enum FooE`
200/// [_EnumTypeDefinition_](https://spec.graphql.org/September2025/#EnumTypeDefinition).
201#[derive(Clone, Debug, Eq, PartialEq, Hash)]
202pub struct EnumTypeDefinition {
203 pub description: Option<Node<str>>,
204 pub name: Name,
205 pub directives: DirectiveList,
206 pub values: Vec<Node<EnumValueDefinition>>,
207}
208
209/// Type system AST for an `input FooIn`
210/// [_InputObjectTypeDefinition_](https://spec.graphql.org/September2025/#InputObjectTypeDefinition).
211#[derive(Clone, Debug, Eq, PartialEq, Hash)]
212pub struct InputObjectTypeDefinition {
213 pub description: Option<Node<str>>,
214 pub name: Name,
215 pub directives: DirectiveList,
216 pub fields: Vec<Node<InputValueDefinition>>,
217}
218
219/// Type system AST for an `extend schema`
220/// [_SchemaExtension_](https://spec.graphql.org/September2025/#SchemaExtension).
221#[derive(Clone, Debug, Eq, PartialEq, Hash)]
222pub struct SchemaExtension {
223 pub directives: DirectiveList,
224 pub root_operations: Vec<Node<(OperationType, NamedType)>>,
225}
226
227/// Type system AST for an `extend scalar FooS`
228/// [_ScalarTypeExtension_](https://spec.graphql.org/September2025/#ScalarTypeExtension).
229#[derive(Clone, Debug, Eq, PartialEq, Hash)]
230pub struct ScalarTypeExtension {
231 pub name: Name,
232 pub directives: DirectiveList,
233}
234
235/// Type system AST for an `extend type FooO`
236/// [_ObjectTypeExtension_](https://spec.graphql.org/September2025/#ObjectTypeExtension).
237#[derive(Clone, Debug, Eq, PartialEq, Hash)]
238pub struct ObjectTypeExtension {
239 pub name: Name,
240 pub implements_interfaces: Vec<Name>,
241 pub directives: DirectiveList,
242 pub fields: Vec<Node<FieldDefinition>>,
243}
244
245/// Type system AST for an `extend interface FooI`
246/// [_InterfaceTypeExtension_](https://spec.graphql.org/September2025/#InterfaceTypeExtension).
247#[derive(Clone, Debug, Eq, PartialEq, Hash)]
248pub struct InterfaceTypeExtension {
249 pub name: Name,
250 pub implements_interfaces: Vec<Name>,
251 pub directives: DirectiveList,
252 pub fields: Vec<Node<FieldDefinition>>,
253}
254
255/// Type system AST for an `extend union FooU`
256/// [_UnionTypeExtension_](https://spec.graphql.org/September2025/#UnionTypeExtension).
257#[derive(Clone, Debug, Eq, PartialEq, Hash)]
258pub struct UnionTypeExtension {
259 pub name: Name,
260 pub directives: DirectiveList,
261 pub members: Vec<NamedType>,
262}
263
264/// Type system AST for an `extend enum FooE`
265/// [_EnumTypeExtension_](https://spec.graphql.org/September2025/#EnumTypeExtension).
266#[derive(Clone, Debug, Eq, PartialEq, Hash)]
267pub struct EnumTypeExtension {
268 pub name: Name,
269 pub directives: DirectiveList,
270 pub values: Vec<Node<EnumValueDefinition>>,
271}
272
273/// Type system AST for an `extend input FooIn`
274/// [_InputObjectTypeExtension_](https://spec.graphql.org/September2025/#InputObjectTypeExtension).
275#[derive(Clone, Debug, Eq, PartialEq, Hash)]
276pub struct InputObjectTypeExtension {
277 pub name: Name,
278 pub directives: DirectiveList,
279 pub fields: Vec<Node<InputValueDefinition>>,
280}
281
282/// AST for an [_Argument_](https://spec.graphql.org/September2025/#Argument)
283/// of a [`Field`] selection or [`Directive`] application.
284#[derive(Clone, Debug, Eq, PartialEq, Hash)]
285pub struct Argument {
286 pub name: Name,
287 pub value: Node<Value>,
288}
289
290/// AST for the list of [_Directives_](https://spec.graphql.org/September2025/#Directives)
291/// applied to some context.
292#[derive(Clone, Eq, PartialEq, Hash, Default)]
293pub struct DirectiveList(pub Vec<Node<Directive>>);
294
295/// AST for a [_Directive_](https://spec.graphql.org/September2025/#Directive) application.
296#[derive(Clone, Debug, Eq, PartialEq, Hash)]
297pub struct Directive {
298 pub name: Name,
299 pub arguments: Vec<Node<Argument>>,
300}
301
302/// AST for the [_OperationType_](https://spec.graphql.org/September2025/#OperationType)
303/// of an [`OperationDefinition`] or [`RootOperationDefinition`][SchemaDefinition::root_operations].
304#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
305pub enum OperationType {
306 Query,
307 Mutation,
308 Subscription,
309}
310
311/// AST for a [_DirectiveLocation_](https://spec.graphql.org/September2025/#DirectiveLocation)
312/// of a [`DirectiveDefinition`].
313#[derive(Copy, Clone, Hash, PartialEq, Eq)]
314pub enum DirectiveLocation {
315 Query,
316 Mutation,
317 Subscription,
318 Field,
319 FragmentDefinition,
320 FragmentSpread,
321 InlineFragment,
322 VariableDefinition,
323 Schema,
324 Scalar,
325 Object,
326 FieldDefinition,
327 ArgumentDefinition,
328 Interface,
329 Union,
330 Enum,
331 EnumValue,
332 InputObject,
333 InputFieldDefinition,
334}
335
336/// Executable AST for a [_VariableDefinition_](https://spec.graphql.org/September2025/#VariableDefinition)
337/// in an [`OperationDefinition`].
338#[derive(Clone, Debug, Eq, PartialEq, Hash)]
339pub struct VariableDefinition {
340 pub description: Option<Node<str>>,
341 pub name: Name,
342 pub ty: Node<Type>,
343 pub default_value: Option<Node<Value>>,
344 pub directives: DirectiveList,
345}
346
347/// Type system AST for a reference to a GraphQL [_Type_](https://spec.graphql.org/September2025/#Type)
348#[derive(Clone, Debug, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
349pub enum Type {
350 /// A `Foo` reference to nullable named type
351 Named(NamedType),
352
353 /// A `Foo!` reference to non-null named type
354 NonNullNamed(NamedType),
355
356 /// A `[…]` reference to nullable list type.
357 /// (The inner item type may or may not be nullable, or a nested list.)
358 List(Box<Type>),
359
360 /// A `[…]!` reference to non-null list type.
361 /// (The inner item type may or may not be nullable, or a nested list.)
362 NonNullList(Box<Type>),
363}
364
365/// Type system AST for a [_FieldDefinition_](https://spec.graphql.org/September2025/#FieldDefinition)
366/// in an object type or interface type defintion or extension.
367#[derive(Clone, Debug, Eq, PartialEq, Hash)]
368pub struct FieldDefinition {
369 pub description: Option<Node<str>>,
370 pub name: Name,
371 pub arguments: Vec<Node<InputValueDefinition>>,
372 pub ty: Type,
373 pub directives: DirectiveList,
374}
375
376/// Type system AST for an
377/// [_InputValueDefinition_](https://spec.graphql.org/September2025/#InputValueDefinition),
378/// a input type field definition or an argument definition.
379#[derive(Clone, Debug, Eq, PartialEq, Hash)]
380pub struct InputValueDefinition {
381 pub description: Option<Node<str>>,
382 pub name: Name,
383 pub ty: Node<Type>,
384 pub default_value: Option<Node<Value>>,
385 pub directives: DirectiveList,
386}
387
388/// Type system AST for an
389/// [_EnumValueDefinition_](https://spec.graphql.org/September2025/#EnumValueDefinition)
390/// in an enum type definition or extension.
391#[derive(Clone, Debug, Eq, PartialEq, Hash)]
392pub struct EnumValueDefinition {
393 pub description: Option<Node<str>>,
394 pub value: Name,
395 pub directives: DirectiveList,
396}
397
398/// Executable AST for a [_Selection_](https://spec.graphql.org/September2025/#Selection)
399/// in a selection set.
400#[derive(Clone, Debug, Eq, PartialEq, Hash)]
401pub enum Selection {
402 Field(Node<Field>),
403 FragmentSpread(Node<FragmentSpread>),
404 InlineFragment(Node<InlineFragment>),
405}
406
407/// Executable AST for a [_Field_](https://spec.graphql.org/September2025/#Field) selection
408/// in a selection set.
409#[derive(Clone, Debug, Eq, PartialEq, Hash)]
410pub struct Field {
411 pub alias: Option<Name>,
412 pub name: Name,
413 pub arguments: Vec<Node<Argument>>,
414 pub directives: DirectiveList,
415 pub selection_set: Vec<Selection>,
416}
417
418/// Executable AST for a
419/// [_FragmentSpread_](https://spec.graphql.org/September2025/#FragmentSpread) selection
420/// in a selection set.
421#[derive(Clone, Debug, Eq, PartialEq, Hash)]
422pub struct FragmentSpread {
423 pub fragment_name: Name,
424 pub directives: DirectiveList,
425}
426
427/// Executable AST for an
428/// [_InlineFragment_](https://spec.graphql.org/September2025/#InlineFragment) selection
429/// in a selection set.
430#[derive(Clone, Debug, Eq, PartialEq, Hash)]
431pub struct InlineFragment {
432 pub type_condition: Option<NamedType>,
433 pub directives: DirectiveList,
434 pub selection_set: Vec<Selection>,
435}
436
437/// Executable AST for a literal GraphQL [_Value_](https://spec.graphql.org/September2025/#Value).
438#[derive(Clone, Debug, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
439pub enum Value {
440 /// A [_NullValue_](https://spec.graphql.org/September2025/#NullValue)
441 Null,
442
443 /// An [_EnumValue_](https://spec.graphql.org/September2025/#EnumValue)
444 Enum(Name),
445
446 /// A [_Variable_](https://spec.graphql.org/September2025/#Variable)
447 Variable(Name),
448
449 /// A [_StringValue_](https://spec.graphql.org/September2025/#StringValue)
450 String(
451 /// The [semantic Unicode text](https://spec.graphql.org/September2025/#sec-String-Value.Static-Semantics)
452 /// that this value represents.
453 String,
454 ),
455
456 /// A [_FloatValue_](https://spec.graphql.org/September2025/#FloatValue)
457 Float(FloatValue),
458
459 /// An [_IntValue_](https://spec.graphql.org/September2025/#IntValue)
460 Int(IntValue),
461
462 /// A [_BooleanValue_](https://spec.graphql.org/September2025/#BooleanValue)
463 Boolean(bool),
464
465 /// A [_ListValue_](https://spec.graphql.org/September2025/#ListValue)
466 List(Vec<Node<Value>>),
467
468 /// An [_ObjectValue_](https://spec.graphql.org/September2025/#ObjectValue)
469 Object(Vec<(Name, Node<Value>)>),
470}
471
472/// An [_IntValue_](https://spec.graphql.org/September2025/#IntValue),
473/// represented as a string in order not to lose range or precision.
474#[derive(Clone, Eq, PartialEq, Hash)]
475pub struct IntValue(String);
476
477/// An [_FloatValue_](https://spec.graphql.org/September2025/#FloatValue),
478/// represented as a string in order not to lose range or precision.
479#[derive(Clone, Eq, PartialEq, Hash)]
480pub struct FloatValue(String);
481
482/// Error type of [`IntValue::try_to_f64`] an [`FloatValue::try_to_f64`]
483/// for conversions that overflow `f64` and would be “rounded” to infinity.
484#[derive(Clone, Eq, PartialEq)]
485#[non_exhaustive]
486pub struct FloatOverflowError {}
487
488/// Error type of [`Directive::argument_by_name`] and
489/// [`Field::argument_by_name`][crate::executable::Field::argument_by_name]
490#[derive(Debug, Clone, PartialEq, Eq)]
491pub enum ArgumentByNameError {
492 /// The directive is not definied in the schema
493 UndefinedDirective,
494 /// The directive or field definition does not define an argument with the requested name
495 NoSuchArgument,
496 /// The argument is required (does not define a default value and has non-null type)
497 /// but not specified
498 RequiredArgumentNotSpecified,
499}