apollo_compiler/ast/
mod.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
//! *Abstract Syntax Tree* for GraphQL documents.
//! An AST [`Document`] is more permissive but lower-level than [`Schema`][crate::Schema]
//! or [`ExecutableDocument`][crate::ExecutableDocument].
//!
//! This AST aims to faithfully represent documents
//! that conform to the GraphQL [syntactic grammar],
//! except that [ignored tokens] such as whitespace are not preserved.
//! These documents may or may not be [valid].
//!
//! Parsing an input that does not conform to the grammar results in parse errors
//! together with a partial AST.
//!
//! [ignored tokens]: https://spec.graphql.org/October2021/#Ignored
//! [syntactic grammar]: https://spec.graphql.org/October2021/#sec-Language
//! [valid]: https://spec.graphql.org/October2021/#sec-Validation
//!
//! ## Parsing
//!
//! Start with [`Document::parse`], or [`Parser`][crate::parser::Parser]
//! to change the parser configuration.
//!
//! ## Structural sharing and mutation
//!
//! Nodes inside documents are wrapped in [`Node`], a reference-counted smart pointer.
//! This allows sharing nodes between documents without cloning entire subtrees.
//! To modify a node, the [`make_mut`][Node::make_mut] method provides copy-on-write semantics.
//!
//! ## Serialization
//!
//! [`Document`] and its node types implement [`Display`][std::fmt::Display]
//! and [`ToString`] by serializing to GraphQL syntax with a default configuration.
//! [`serialize`][Document::serialize] methods return a builder
//! that has chaining methods for setting serialization configuration,
//! and also implements `Display` and `ToString`.
//!
//! ## Example
//!
//! ```
//! use apollo_compiler::{ast, name};
//!
//! let source = "{field}";
//! let mut doc = ast::Document::parse(source, "example.graphql").unwrap();
//! for def in &mut doc.definitions {
//!     if let ast::Definition::OperationDefinition(op) = def {
//!         // `op` has type `&mut Node<ast::OperationDefinition>`
//!         // `Node` implements `Deref` but not `DeferMut`
//!         // `make_mut()` clones if necessary and returns `&mut ast::OperationDefinition`
//!         op.make_mut().directives.push(ast::Directive::new(name!(dir)));
//!     }
//! }
//! assert_eq!(doc.serialize().no_indent().to_string(), "query @dir { field }")
//! ```

use crate::parser::SourceMap;
use crate::Name;
use crate::Node;

pub(crate) mod from_cst;
pub(crate) mod impls;
pub(crate) mod serialize;

pub use self::serialize::Serialize;

/// AST for a GraphQL [_Document_](https://spec.graphql.org/draft/#Document)
/// that can contain executable definitions, type system (schema) definitions, or both.
///
/// It is typically parsed from one `&str` input “file” but can be also be synthesized
/// programatically.
#[derive(Clone)]
pub struct Document {
    /// If this document was originally parsed from a source file,
    /// this map contains one entry for that file and its ID.
    ///
    /// The document is [mutable][crate::ast#structural-sharing-and-mutation]
    /// so it may have been modified since.
    pub sources: SourceMap,

    pub definitions: Vec<Definition>,
}

const _: () = {
    const fn assert_send<T: Send>() {}
    const fn assert_sync<T: Sync>() {}
    assert_send::<Document>();
    assert_sync::<Document>();
};

/// A [_NamedType_](https://spec.graphql.org/draft/#NamedType)
/// references by name a GraphQL type defined elsewhere.
pub type NamedType = Name;

/// AST for a top-level [_Definition_](https://spec.graphql.org/draft/#Definition) of any kind:
/// executable, type system, or type system extension.
#[derive(Clone, Eq, PartialEq, Hash)]
pub enum Definition {
    OperationDefinition(Node<OperationDefinition>),
    FragmentDefinition(Node<FragmentDefinition>),
    DirectiveDefinition(Node<DirectiveDefinition>),
    SchemaDefinition(Node<SchemaDefinition>),
    ScalarTypeDefinition(Node<ScalarTypeDefinition>),
    ObjectTypeDefinition(Node<ObjectTypeDefinition>),
    InterfaceTypeDefinition(Node<InterfaceTypeDefinition>),
    UnionTypeDefinition(Node<UnionTypeDefinition>),
    EnumTypeDefinition(Node<EnumTypeDefinition>),
    InputObjectTypeDefinition(Node<InputObjectTypeDefinition>),
    SchemaExtension(Node<SchemaExtension>),
    ScalarTypeExtension(Node<ScalarTypeExtension>),
    ObjectTypeExtension(Node<ObjectTypeExtension>),
    InterfaceTypeExtension(Node<InterfaceTypeExtension>),
    UnionTypeExtension(Node<UnionTypeExtension>),
    EnumTypeExtension(Node<EnumTypeExtension>),
    InputObjectTypeExtension(Node<InputObjectTypeExtension>),
}

/// Executable AST for an
/// [_OperationDefinition_](https://spec.graphql.org/draft/#OperationDefinition).
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct OperationDefinition {
    pub operation_type: OperationType,
    pub name: Option<Name>,
    pub variables: Vec<Node<VariableDefinition>>,
    pub directives: DirectiveList,
    pub selection_set: Vec<Selection>,
}

/// Executable AST for a
/// [_FragmentDefinition_](https://spec.graphql.org/draft/#FragmentDefinition).
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct FragmentDefinition {
    pub name: Name,
    pub type_condition: NamedType,
    pub directives: DirectiveList,
    pub selection_set: Vec<Selection>,
}

/// Type system AST for a `directive @foo`
/// [_DirectiveDefinition_](https://spec.graphql.org/draft/#DirectiveDefinition).
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct DirectiveDefinition {
    pub description: Option<Node<str>>,
    pub name: Name,
    pub arguments: Vec<Node<InputValueDefinition>>,
    pub repeatable: bool,
    pub locations: Vec<DirectiveLocation>,
}

/// Type system AST for a `schema`
/// [_SchemaDefinition_](https://spec.graphql.org/draft/#SchemaDefinition).
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct SchemaDefinition {
    pub description: Option<Node<str>>,
    pub directives: DirectiveList,
    pub root_operations: Vec<Node<(OperationType, NamedType)>>,
}

/// Type system AST for a `scalar FooS`
/// [_ScalarTypeDefinition_](https://spec.graphql.org/draft/#ScalarTypeDefinition).
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct ScalarTypeDefinition {
    pub description: Option<Node<str>>,
    pub name: Name,
    pub directives: DirectiveList,
}

/// Type system AST for a `type FooO`
/// [_ObjectTypeDefinition_](https://spec.graphql.org/draft/#ObjectTypeDefinition).
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct ObjectTypeDefinition {
    pub description: Option<Node<str>>,
    pub name: Name,
    pub implements_interfaces: Vec<Name>,
    pub directives: DirectiveList,
    pub fields: Vec<Node<FieldDefinition>>,
}

/// Type system AST for an `interface FooI`
/// [_InterfaceTypeDefinition_](https://spec.graphql.org/draft/#InterfaceTypeDefinition).
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct InterfaceTypeDefinition {
    pub description: Option<Node<str>>,
    pub name: Name,
    pub implements_interfaces: Vec<Name>,
    pub directives: DirectiveList,
    pub fields: Vec<Node<FieldDefinition>>,
}

/// Type system AST for a `union FooU`
/// [_UnionTypeDefinition_](https://spec.graphql.org/draft/#UnionTypeDefinition).
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct UnionTypeDefinition {
    pub description: Option<Node<str>>,
    pub name: Name,
    pub directives: DirectiveList,
    pub members: Vec<NamedType>,
}

/// Type system AST for an `enum FooE`
/// [_EnumTypeDefinition_](https://spec.graphql.org/draft/#EnumTypeDefinition).
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct EnumTypeDefinition {
    pub description: Option<Node<str>>,
    pub name: Name,
    pub directives: DirectiveList,
    pub values: Vec<Node<EnumValueDefinition>>,
}

/// Type system AST for an `input FooIn`
/// [_InputObjectTypeDefinition_](https://spec.graphql.org/draft/#InputObjectTypeDefinition).
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct InputObjectTypeDefinition {
    pub description: Option<Node<str>>,
    pub name: Name,
    pub directives: DirectiveList,
    pub fields: Vec<Node<InputValueDefinition>>,
}

/// Type system AST for an `extend schema`
/// [_SchemaExtension_](https://spec.graphql.org/draft/#SchemaExtension).
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct SchemaExtension {
    pub directives: DirectiveList,
    pub root_operations: Vec<Node<(OperationType, NamedType)>>,
}

/// Type system AST for an `extend scalar FooS`
/// [_ScalarTypeExtension_](https://spec.graphql.org/draft/#ScalarTypeExtension).
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct ScalarTypeExtension {
    pub name: Name,
    pub directives: DirectiveList,
}

/// Type system AST for an `extend type FooO`
/// [_ObjectTypeExtension_](https://spec.graphql.org/draft/#ObjectTypeExtension).
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct ObjectTypeExtension {
    pub name: Name,
    pub implements_interfaces: Vec<Name>,
    pub directives: DirectiveList,
    pub fields: Vec<Node<FieldDefinition>>,
}

/// Type system AST for an `extend interface FooI`
/// [_InterfaceTypeExtension_](https://spec.graphql.org/draft/#InterfaceTypeExtension).
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct InterfaceTypeExtension {
    pub name: Name,
    pub implements_interfaces: Vec<Name>,
    pub directives: DirectiveList,
    pub fields: Vec<Node<FieldDefinition>>,
}

/// Type system AST for an `extend union FooU`
/// [_UnionTypeExtension_](https://spec.graphql.org/draft/#UnionTypeExtension).
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct UnionTypeExtension {
    pub name: Name,
    pub directives: DirectiveList,
    pub members: Vec<NamedType>,
}

/// Type system AST for an `extend enum FooE`
/// [_EnumTypeExtension_](https://spec.graphql.org/draft/#EnumTypeExtension).
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct EnumTypeExtension {
    pub name: Name,
    pub directives: DirectiveList,
    pub values: Vec<Node<EnumValueDefinition>>,
}

/// Type system AST for an `extend input FooIn`
/// [_InputObjectTypeExtension_](https://spec.graphql.org/draft/#InputObjectTypeExtension).
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct InputObjectTypeExtension {
    pub name: Name,
    pub directives: DirectiveList,
    pub fields: Vec<Node<InputValueDefinition>>,
}

/// AST for an [_Argument_](https://spec.graphql.org/draft/#Argument)
/// of a [`Field`] selection or [`Directive`] application.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct Argument {
    pub name: Name,
    pub value: Node<Value>,
}

/// AST for the list of [_Directives_](https://spec.graphql.org/draft/#Directives)
/// applied to some context.
#[derive(Clone, Eq, PartialEq, Hash, Default)]
pub struct DirectiveList(pub Vec<Node<Directive>>);

/// AST for a [_Directive_](https://spec.graphql.org/draft/#Directive) application.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct Directive {
    pub name: Name,
    pub arguments: Vec<Node<Argument>>,
}

/// AST for the [_OperationType_](https://spec.graphql.org/draft/#OperationType)
/// of an [`OperationDefinition`] or [`RootOperationDefinition`][SchemaDefinition::root_operations].
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub enum OperationType {
    Query,
    Mutation,
    Subscription,
}

/// AST for a [_DirectiveLocation_](https://spec.graphql.org/draft/#DirectiveLocation)
/// of a [`DirectiveDefinition`].
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
pub enum DirectiveLocation {
    Query,
    Mutation,
    Subscription,
    Field,
    FragmentDefinition,
    FragmentSpread,
    InlineFragment,
    VariableDefinition,
    Schema,
    Scalar,
    Object,
    FieldDefinition,
    ArgumentDefinition,
    Interface,
    Union,
    Enum,
    EnumValue,
    InputObject,
    InputFieldDefinition,
}

/// Executable AST for a [_VariableDefinition_](https://spec.graphql.org/draft/#VariableDefinition)
/// in an [`OperationDefinition`].
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct VariableDefinition {
    pub name: Name,
    pub ty: Node<Type>,
    pub default_value: Option<Node<Value>>,
    pub directives: DirectiveList,
}

/// Type system AST for a reference to a GraphQL [_Type_](https://spec.graphql.org/draft/#Type)
#[derive(Clone, Debug, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
pub enum Type {
    /// A `Foo` reference to nullable named type
    Named(NamedType),

    /// A `Foo!` reference to non-null named type
    NonNullNamed(NamedType),

    /// A `[…]` reference to nullable list type.
    /// (The inner item type may or may not be nullable, or a nested list.)
    List(Box<Type>),

    /// A `[…]!` reference to non-null list type.
    /// (The inner item type may or may not be nullable, or a nested list.)
    NonNullList(Box<Type>),
}

/// Type system AST for a [_FieldDefinition_](https://spec.graphql.org/draft/#FieldDefinition)
/// in an object type or interface type defintion or extension.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct FieldDefinition {
    pub description: Option<Node<str>>,
    pub name: Name,
    pub arguments: Vec<Node<InputValueDefinition>>,
    pub ty: Type,
    pub directives: DirectiveList,
}

/// Type system AST for an
/// [_InputValueDefinition_](https://spec.graphql.org/draft/#InputValueDefinition),
/// a input type field definition or an argument definition.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct InputValueDefinition {
    pub description: Option<Node<str>>,
    pub name: Name,
    pub ty: Node<Type>,
    pub default_value: Option<Node<Value>>,
    pub directives: DirectiveList,
}

/// Type system AST for an
/// [_EnumValueDefinition_](https://spec.graphql.org/draft/#EnumValueDefinition)
/// in an enum type definition or extension.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct EnumValueDefinition {
    pub description: Option<Node<str>>,
    pub value: Name,
    pub directives: DirectiveList,
}

/// Executable AST for a [_Selection_](https://spec.graphql.org/draft/#Selection)
/// in a selection set.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum Selection {
    Field(Node<Field>),
    FragmentSpread(Node<FragmentSpread>),
    InlineFragment(Node<InlineFragment>),
}

/// Executable AST for a [_Field_](https://spec.graphql.org/draft/#Field) selection
/// in a selection set.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct Field {
    pub alias: Option<Name>,
    pub name: Name,
    pub arguments: Vec<Node<Argument>>,
    pub directives: DirectiveList,
    pub selection_set: Vec<Selection>,
}

/// Executable AST for a
/// [_FragmentSpread_](https://spec.graphql.org/draft/#FragmentSpread) selection
/// in a selection set.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct FragmentSpread {
    pub fragment_name: Name,
    pub directives: DirectiveList,
}

/// Executable AST for an
/// [_InlineFragment_](https://spec.graphql.org/draft/#InlineFragment) selection
/// in a selection set.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct InlineFragment {
    pub type_condition: Option<NamedType>,
    pub directives: DirectiveList,
    pub selection_set: Vec<Selection>,
}

/// Executable AST for a literal GraphQL [_Value_](https://spec.graphql.org/draft/#Value).
#[derive(Clone, Debug, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
pub enum Value {
    /// A [_NullValue_](https://spec.graphql.org/draft/#NullValue)
    Null,

    /// An [_EnumValue_](https://spec.graphql.org/draft/#EnumValue)
    Enum(Name),

    /// A [_Variable_](https://spec.graphql.org/draft/#Variable)
    Variable(Name),

    /// A [_StringValue_](https://spec.graphql.org/draft/#StringValue)
    String(
        /// The [semantic Unicode text](https://spec.graphql.org/draft/#sec-String-Value.Static-Semantics)
        /// that this value represents.
        String,
    ),

    /// A [_FloatValue_](https://spec.graphql.org/draft/#FloatValue)
    Float(FloatValue),

    /// An [_IntValue_](https://spec.graphql.org/draft/#IntValue)
    Int(IntValue),

    /// A [_BooleanValue_](https://spec.graphql.org/draft/#BooleanValue)
    Boolean(bool),

    /// A [_ListValue_](https://spec.graphql.org/draft/#ListValue)
    List(Vec<Node<Value>>),

    /// An [_ObjectValue_](https://spec.graphql.org/draft/#ObjectValue)
    Object(Vec<(Name, Node<Value>)>),
}

/// An [_IntValue_](https://spec.graphql.org/draft/#IntValue),
/// represented as a string in order not to lose range or precision.
#[derive(Clone, Eq, PartialEq, Hash)]
pub struct IntValue(String);

/// An [_FloatValue_](https://spec.graphql.org/draft/#FloatValue),
/// represented as a string in order not to lose range or precision.
#[derive(Clone, Eq, PartialEq, Hash)]
pub struct FloatValue(String);

/// Error type of [`IntValue::try_to_f64`] an  [`FloatValue::try_to_f64`]
/// for conversions that overflow `f64` and would be “rounded” to infinity.
#[derive(Clone, Eq, PartialEq)]
#[non_exhaustive]
pub struct FloatOverflowError {}

/// Error type of [`Directive::argument_by_name`] and
/// [`Field::argument_by_name`][crate::executable::Field::argument_by_name]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ArgumentByNameError {
    /// The directive is not definied in the schema
    UndefinedDirective,
    /// The directive or field definition does not define an argument with the requested name
    NoSuchArgument,
    /// The argument is required (does not define a default value and has non-null type)
    /// but not specified
    RequiredArgumentNotSpecified,
}