Skip to main content

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}