1use super::*;
2use crate::ast::OperationType;
3use crate::validation::WithErrors;
4use indexmap::map::Entry;
5use std::sync::Arc;
6
7#[derive(Clone)]
8pub struct SchemaBuilder {
9 adopt_orphan_extensions: bool,
10 pub(crate) schema: Schema,
11 schema_definition: SchemaDefinitionStatus,
12 orphan_type_extensions: IndexMap<Name, Vec<ast::Definition>>,
13 pub(crate) errors: DiagnosticList,
14}
15
16#[derive(Clone)]
17enum SchemaDefinitionStatus {
18 Found,
19 NoneSoFar {
20 orphan_extensions: Vec<Node<ast::SchemaExtension>>,
21 },
22}
23
24impl Default for SchemaBuilder {
25 fn default() -> Self {
26 Self::new()
27 }
28}
29
30impl SchemaBuilder {
31 pub(crate) fn built_in() -> &'static Self {
32 static BUILT_IN: std::sync::OnceLock<SchemaBuilder> = std::sync::OnceLock::new();
33 BUILT_IN.get_or_init(|| {
34 let mut builder = SchemaBuilder {
35 adopt_orphan_extensions: false,
36 schema: Schema {
37 sources: Default::default(),
38 schema_definition: Node::new(SchemaDefinition {
39 description: None,
40 directives: DirectiveList::default(),
41 query: None,
42 mutation: None,
43 subscription: None,
44 }),
45 directive_definitions: IndexMap::with_hasher(Default::default()),
46 types: IndexMap::with_hasher(Default::default()),
47 },
48 schema_definition: SchemaDefinitionStatus::NoneSoFar {
49 orphan_extensions: Vec::new(),
50 },
51 orphan_type_extensions: IndexMap::with_hasher(Default::default()),
52 errors: DiagnosticList::new(Default::default()),
53 };
54 let input = include_str!("../built_in_types.graphql").to_owned();
55 let path = "built_in.graphql";
56 let id = FileId::BUILT_IN;
57 let ast = ast::Document::parser().parse_ast_inner(input, path, id, &mut builder.errors);
58 let executable_definitions_are_errors = true;
59 builder.add_ast_document(&ast, executable_definitions_are_errors);
60 assert!(builder.errors.is_empty());
61 builder
62 })
63 }
64
65 pub fn new() -> Self {
68 Self::built_in().clone()
69 }
70
71 pub fn adopt_orphan_extensions(mut self) -> Self {
75 self.adopt_orphan_extensions = true;
76 self
77 }
78
79 pub fn parse(mut self, source_text: impl Into<String>, path: impl AsRef<Path>) -> Self {
83 Parser::new().parse_into_schema_builder(source_text, path, &mut self);
84 self
85 }
86
87 pub fn add_ast(mut self, document: &ast::Document) -> Self {
91 let executable_definitions_are_errors = true;
92 self.add_ast_document(document, executable_definitions_are_errors);
93 self
94 }
95
96 pub(crate) fn add_ast_document(
97 &mut self,
98 document: &ast::Document,
99 executable_definitions_are_errors: bool,
100 ) {
101 Arc::make_mut(&mut self.errors.sources)
102 .extend(document.sources.iter().map(|(k, v)| (*k, v.clone())));
103 self.add_ast_document_not_adding_sources(document, executable_definitions_are_errors)
104 }
105
106 pub(crate) fn add_ast_document_not_adding_sources(
107 &mut self,
108 document: &ast::Document,
109 executable_definitions_are_errors: bool,
110 ) {
111 for definition in &document.definitions {
112 macro_rules! type_definition {
113 ($def: ident, $Type: ident, is_scalar = $is_scalar: literal) => {
114 match self.schema.types.entry($def.name.clone()) {
115 Entry::Vacant(entry) => {
116 let extended_def = $Type::from_ast(
117 &mut self.errors,
118 $def,
119 self.orphan_type_extensions
120 .shift_remove(&$def.name)
121 .unwrap_or_default(),
122 );
123 entry.insert(extended_def.into());
124 }
125 Entry::Occupied(entry) => {
126 let previous = entry.get();
127 if $is_scalar && previous.is_built_in() {
128 self.errors.push(
129 $def.location(),
130 BuildError::BuiltInScalarTypeRedefinition,
131 )
132 } else {
133 self.errors.push(
134 $def.name.location(),
135 BuildError::TypeDefinitionCollision {
136 previous_location: previous.name().location(),
137 name: $def.name.clone(),
138 },
139 )
140 }
141 }
142 }
143 };
144 }
145 macro_rules! type_extension {
146 ($ext: ident, $Kind: ident) => {
147 if let Some(ty) = self.schema.types.get_mut(&$ext.name) {
148 if let ExtendedType::$Kind(ty) = ty {
149 ty.make_mut().extend_ast(&mut self.errors, $ext)
150 } else {
151 self.errors.push(
152 $ext.name.location(),
153 BuildError::TypeExtensionKindMismatch {
154 name: $ext.name.clone(),
155 describe_ext: definition.describe(),
156 def_location: ty.name().location(),
157 describe_def: ty.describe(),
158 },
159 )
160 }
161 } else {
162 self.orphan_type_extensions
163 .entry($ext.name.clone())
164 .or_default()
165 .push(definition.clone())
166 }
167 };
168 }
169 match definition {
170 ast::Definition::SchemaDefinition(def) => match &self.schema_definition {
171 SchemaDefinitionStatus::NoneSoFar { orphan_extensions } => {
172 self.schema.schema_definition =
173 SchemaDefinition::from_ast(&mut self.errors, def, orphan_extensions);
174 self.schema_definition = SchemaDefinitionStatus::Found;
175 }
176 SchemaDefinitionStatus::Found => self.errors.push(
177 def.location(),
178 BuildError::SchemaDefinitionCollision {
179 previous_location: self.schema.schema_definition.location(),
180 },
181 ),
182 },
183 ast::Definition::DirectiveDefinition(def) => {
184 match self.schema.directive_definitions.entry(def.name.clone()) {
185 Entry::Vacant(entry) => {
186 entry.insert(def.clone());
187 }
188 Entry::Occupied(mut entry) => {
189 let previous = entry.get_mut();
190 if previous.is_built_in() {
191 *previous = def.clone()
196 } else {
197 self.errors.push(
198 def.name.location(),
199 BuildError::DirectiveDefinitionCollision {
200 previous_location: previous.name.location(),
201 name: def.name.clone(),
202 },
203 )
204 }
205 }
206 }
207 }
208 ast::Definition::ScalarTypeDefinition(def) => {
209 type_definition!(def, ScalarType, is_scalar = true)
210 }
211 ast::Definition::ObjectTypeDefinition(def) => {
212 type_definition!(def, ObjectType, is_scalar = false)
213 }
214 ast::Definition::InterfaceTypeDefinition(def) => {
215 type_definition!(def, InterfaceType, is_scalar = false)
216 }
217 ast::Definition::UnionTypeDefinition(def) => {
218 type_definition!(def, UnionType, is_scalar = false)
219 }
220 ast::Definition::EnumTypeDefinition(def) => {
221 type_definition!(def, EnumType, is_scalar = false)
222 }
223 ast::Definition::InputObjectTypeDefinition(def) => {
224 type_definition!(def, InputObjectType, is_scalar = false)
225 }
226 ast::Definition::SchemaExtension(ext) => match &mut self.schema_definition {
227 SchemaDefinitionStatus::Found => self
228 .schema
229 .schema_definition
230 .make_mut()
231 .extend_ast(&mut self.errors, ext),
232 SchemaDefinitionStatus::NoneSoFar { orphan_extensions } => {
233 orphan_extensions.push(ext.clone())
234 }
235 },
236 ast::Definition::ScalarTypeExtension(ext) => type_extension!(ext, Scalar),
237 ast::Definition::ObjectTypeExtension(ext) => type_extension!(ext, Object),
238 ast::Definition::InterfaceTypeExtension(ext) => type_extension!(ext, Interface),
239 ast::Definition::UnionTypeExtension(ext) => type_extension!(ext, Union),
240 ast::Definition::EnumTypeExtension(ext) => type_extension!(ext, Enum),
241 ast::Definition::InputObjectTypeExtension(ext) => type_extension!(ext, InputObject),
242 ast::Definition::OperationDefinition(_)
243 | ast::Definition::FragmentDefinition(_) => {
244 if executable_definitions_are_errors {
245 self.errors.push(
246 definition.location(),
247 BuildError::ExecutableDefinition {
248 describe: definition.describe(),
249 },
250 )
251 }
252 }
253 }
254 }
255 }
256
257 #[allow(clippy::result_large_err)] pub fn build(self) -> Result<Schema, WithErrors<Schema>> {
260 let (schema, errors) = self.build_inner();
261 errors.into_result_with(schema)
262 }
263
264 pub(crate) fn build_inner(self) -> (Schema, DiagnosticList) {
265 let SchemaBuilder {
266 adopt_orphan_extensions,
267 mut schema,
268 schema_definition,
269 orphan_type_extensions,
270 mut errors,
271 } = self;
272 schema.sources = errors.sources.clone();
273 match schema_definition {
274 SchemaDefinitionStatus::Found => {}
275 SchemaDefinitionStatus::NoneSoFar { orphan_extensions } => {
276 let schema_def = schema.schema_definition.make_mut();
278 if adopt_orphan_extensions {
279 for ext in &orphan_extensions {
283 schema_def.extend_ast(&mut errors, ext)
284 }
285 if schema_def.query.is_none()
286 && schema_def.mutation.is_none()
287 && schema_def.subscription.is_none()
288 {
289 add_implicit_root_types(schema_def, &schema.types);
290 }
291 } else {
292 let has_implicit_root_operation =
293 add_implicit_root_types(schema_def, &schema.types);
294 if has_implicit_root_operation {
295 for ext in &orphan_extensions {
301 schema_def.extend_ast(&mut errors, ext)
302 }
303 } else {
304 for ext in &orphan_extensions {
305 errors.push(ext.location(), BuildError::OrphanSchemaExtension)
306 }
307 }
308 }
309 }
310 }
311 if adopt_orphan_extensions {
313 for (type_name, extensions) in orphan_type_extensions {
314 let type_def = adopt_type_extensions(&mut errors, &type_name, &extensions);
315 let previous = schema.types.insert(type_name, type_def);
316 assert!(previous.is_none());
317 }
318 } else {
319 for extensions in orphan_type_extensions.values() {
320 for ext in extensions {
321 let name = ext.name().unwrap().clone();
322 errors.push(name.location(), BuildError::OrphanTypeExtension { name })
323 }
324 }
325 }
326 (schema, errors)
327 }
328}
329
330fn add_implicit_root_types(
331 schema_def: &mut SchemaDefinition,
332 types: &IndexMap<Name, ExtendedType>,
333) -> bool {
334 let mut has_implicit_root_operation = false;
335 for (operation_type, root_operation) in [
336 (OperationType::Query, &mut schema_def.query),
337 (OperationType::Mutation, &mut schema_def.mutation),
338 (OperationType::Subscription, &mut schema_def.subscription),
339 ] {
340 let name = operation_type.default_type_name();
341 if types.get(&name).is_some_and(|def| def.is_object()) {
342 *root_operation = Some(name.into());
343 has_implicit_root_operation = true
344 }
345 }
346 has_implicit_root_operation
347}
348
349fn adopt_type_extensions(
350 errors: &mut DiagnosticList,
351 type_name: &Name,
352 extensions: &[ast::Definition],
353) -> ExtendedType {
354 macro_rules! extend {
355 ($( $ExtensionVariant: path => $describe: literal $empty_def: expr )+) => {
356 match &extensions[0] {
357 $(
358 $ExtensionVariant(_) => {
359 let mut def = $empty_def;
360 for ext in extensions {
361 if let $ExtensionVariant(ext) = ext {
362 def.extend_ast(errors, ext)
363 } else {
364 let ext_name = ext.name().unwrap();
365 errors.push(
366 ext_name.location(),
367 BuildError::TypeExtensionKindMismatch {
368 name: ext_name.clone(),
369 describe_ext: ext.describe(),
370 def_location: type_name.location(),
371 describe_def: $describe,
372 }
373 )
374 }
375 }
376 def.into()
377 }
378 )+
379 _ => unreachable!(),
380 }
381 };
382 }
383 let name = type_name.clone();
384 extend! {
385 ast::Definition::ScalarTypeExtension => "a scalar type" ScalarType {
386 description: Default::default(),
387 name,
388 directives: Default::default(),
389 }
390 ast::Definition::ObjectTypeExtension => "an object type" ObjectType {
391 description: Default::default(),
392 name,
393 implements_interfaces: Default::default(),
394 directives: Default::default(),
395 fields: Default::default(),
396 }
397 ast::Definition::InterfaceTypeExtension => "an interface type" InterfaceType {
398 description: Default::default(),
399 name,
400 implements_interfaces: Default::default(),
401 directives: Default::default(),
402 fields: Default::default(),
403 }
404 ast::Definition::UnionTypeExtension => "a union type" UnionType {
405 description: Default::default(),
406 name,
407 directives: Default::default(),
408 members: Default::default(),
409 }
410 ast::Definition::EnumTypeExtension => "an enum type" EnumType {
411 description: Default::default(),
412 name,
413 directives: Default::default(),
414 values: Default::default(),
415 }
416 ast::Definition::InputObjectTypeExtension => "an input object type" InputObjectType {
417 description: Default::default(),
418 name,
419 directives: Default::default(),
420 fields: Default::default(),
421 }
422 }
423}
424
425impl SchemaDefinition {
426 fn from_ast(
427 errors: &mut DiagnosticList,
428 definition: &Node<ast::SchemaDefinition>,
429 extensions: &[Node<ast::SchemaExtension>],
430 ) -> Node<Self> {
431 let mut root = Self {
432 description: definition.description.clone(),
433 directives: definition
434 .directives
435 .iter()
436 .map(|d| d.to_component(ComponentOrigin::Definition))
437 .collect(),
438 query: None,
439 mutation: None,
440 subscription: None,
441 };
442 root.add_root_operations(
443 errors,
444 ComponentOrigin::Definition,
445 &definition.root_operations,
446 );
447 for ext in extensions {
448 root.extend_ast(errors, ext)
449 }
450 definition.same_location(root)
451 }
452
453 fn extend_ast(&mut self, errors: &mut DiagnosticList, extension: &Node<ast::SchemaExtension>) {
454 let origin = ComponentOrigin::Extension(ExtensionId::new(extension));
455 self.directives.extend(
456 extension
457 .directives
458 .iter()
459 .map(|d| d.to_component(origin.clone())),
460 );
461 self.add_root_operations(errors, origin, &extension.root_operations)
462 }
463
464 fn add_root_operations(
465 &mut self,
466 errors: &mut DiagnosticList,
467 origin: ComponentOrigin,
468 root_operations: &[Node<(OperationType, Name)>],
469 ) {
470 for op in root_operations {
471 let (operation_type, object_type_name) = &**op;
472 let entry = match operation_type {
473 OperationType::Query => &mut self.query,
474 OperationType::Mutation => &mut self.mutation,
475 OperationType::Subscription => &mut self.subscription,
476 };
477 match entry {
478 None => *entry = Some(object_type_name.to_component(origin.clone())),
479 Some(previous) => errors.push(
480 op.location(),
481 BuildError::DuplicateRootOperation {
482 previous_location: previous.location(),
483 operation_type: operation_type.name(),
484 },
485 ),
486 }
487 }
488 }
489}
490
491impl ScalarType {
492 fn from_ast(
493 errors: &mut DiagnosticList,
494 definition: &Node<ast::ScalarTypeDefinition>,
495 extensions: Vec<ast::Definition>,
496 ) -> Node<Self> {
497 let mut ty = Self {
498 description: definition.description.clone(),
499 name: definition.name.clone(),
500 directives: definition
501 .directives
502 .iter()
503 .map(|d| d.to_component(ComponentOrigin::Definition))
504 .collect(),
505 };
506 for def in &extensions {
507 if let ast::Definition::ScalarTypeExtension(ext) = def {
508 ty.extend_ast(errors, ext)
509 }
510 }
511 definition.same_location(ty)
512 }
513
514 fn extend_ast(
515 &mut self,
516 _errors: &mut DiagnosticList,
517 extension: &Node<ast::ScalarTypeExtension>,
518 ) {
519 let origin = ComponentOrigin::Extension(ExtensionId::new(extension));
520 self.directives.extend(
521 extension
522 .directives
523 .iter()
524 .map(|d| d.to_component(origin.clone())),
525 );
526 }
527}
528
529impl ObjectType {
530 fn from_ast(
531 errors: &mut DiagnosticList,
532 definition: &Node<ast::ObjectTypeDefinition>,
533 extensions: Vec<ast::Definition>,
534 ) -> Node<Self> {
535 let mut ty = Self {
536 description: definition.description.clone(),
537 name: definition.name.clone(),
538 implements_interfaces: collect_sticky_set(
539 definition
540 .implements_interfaces
541 .iter()
542 .map(|name| name.to_component(ComponentOrigin::Definition)),
543 |prev, dup| {
544 errors.push(
545 dup.location(),
546 BuildError::DuplicateImplementsInterfaceInObject {
547 name_at_previous_location: prev.name.clone(),
548 type_name: definition.name.clone(),
549 },
550 )
551 },
552 ),
553 directives: definition
554 .directives
555 .iter()
556 .map(|d| d.to_component(ComponentOrigin::Definition))
557 .collect(),
558 fields: collect_sticky(
559 definition
560 .fields
561 .iter()
562 .map(|field| (&field.name, field.to_component(ComponentOrigin::Definition))),
563 |prev_key, dup_value| {
564 errors.push(
565 dup_value.location(),
566 BuildError::ObjectFieldNameCollision {
567 name_at_previous_location: prev_key.clone(),
568 type_name: definition.name.clone(),
569 },
570 )
571 },
572 ),
573 };
574 for def in &extensions {
575 if let ast::Definition::ObjectTypeExtension(ext) = def {
576 ty.extend_ast(errors, ext)
577 }
578 }
579 definition.same_location(ty)
580 }
581
582 fn extend_ast(
583 &mut self,
584 errors: &mut DiagnosticList,
585 extension: &Node<ast::ObjectTypeExtension>,
586 ) {
587 let origin = ComponentOrigin::Extension(ExtensionId::new(extension));
588 self.directives.extend(
589 extension
590 .directives
591 .iter()
592 .map(|d| d.to_component(origin.clone())),
593 );
594 extend_sticky_set(
595 &mut self.implements_interfaces,
596 extension
597 .implements_interfaces
598 .iter()
599 .map(|name| name.to_component(origin.clone())),
600 |prev, dup| {
601 errors.push(
602 dup.location(),
603 BuildError::DuplicateImplementsInterfaceInObject {
604 name_at_previous_location: prev.name.clone(),
605 type_name: extension.name.clone(),
606 },
607 )
608 },
609 );
610 extend_sticky(
611 &mut self.fields,
612 extension
613 .fields
614 .iter()
615 .map(|field| (&field.name, field.to_component(origin.clone()))),
616 |prev_key, dup_value| {
617 errors.push(
618 dup_value.location(),
619 BuildError::ObjectFieldNameCollision {
620 name_at_previous_location: prev_key.clone(),
621 type_name: extension.name.clone(),
622 },
623 )
624 },
625 );
626 }
627}
628
629impl InterfaceType {
630 fn from_ast(
631 errors: &mut DiagnosticList,
632 definition: &Node<ast::InterfaceTypeDefinition>,
633 extensions: Vec<ast::Definition>,
634 ) -> Node<Self> {
635 let mut ty = Self {
636 description: definition.description.clone(),
637 name: definition.name.clone(),
638 implements_interfaces: collect_sticky_set(
639 definition
640 .implements_interfaces
641 .iter()
642 .map(|name| name.to_component(ComponentOrigin::Definition)),
643 |prev, dup| {
644 errors.push(
645 dup.location(),
646 BuildError::DuplicateImplementsInterfaceInInterface {
647 name_at_previous_location: prev.name.clone(),
648 type_name: definition.name.clone(),
649 },
650 )
651 },
652 ),
653 directives: definition
654 .directives
655 .iter()
656 .map(|d| d.to_component(ComponentOrigin::Definition))
657 .collect(),
658 fields: collect_sticky(
659 definition
660 .fields
661 .iter()
662 .map(|field| (&field.name, field.to_component(ComponentOrigin::Definition))),
663 |prev_key, dup_value| {
664 errors.push(
665 dup_value.location(),
666 BuildError::InterfaceFieldNameCollision {
667 name_at_previous_location: prev_key.clone(),
668 type_name: definition.name.clone(),
669 },
670 )
671 },
672 ),
673 };
674 for def in &extensions {
675 if let ast::Definition::InterfaceTypeExtension(ext) = def {
676 ty.extend_ast(errors, ext)
677 }
678 }
679 definition.same_location(ty)
680 }
681
682 fn extend_ast(
683 &mut self,
684 errors: &mut DiagnosticList,
685 extension: &Node<ast::InterfaceTypeExtension>,
686 ) {
687 let origin = ComponentOrigin::Extension(ExtensionId::new(extension));
688 self.directives.extend(
689 extension
690 .directives
691 .iter()
692 .map(|d| d.to_component(origin.clone())),
693 );
694 extend_sticky_set(
695 &mut self.implements_interfaces,
696 extension
697 .implements_interfaces
698 .iter()
699 .map(|name| name.to_component(origin.clone())),
700 |prev, dup| {
701 errors.push(
702 dup.location(),
703 BuildError::DuplicateImplementsInterfaceInInterface {
704 name_at_previous_location: prev.name.clone(),
705 type_name: extension.name.clone(),
706 },
707 )
708 },
709 );
710 extend_sticky(
711 &mut self.fields,
712 extension
713 .fields
714 .iter()
715 .map(|field| (&field.name, field.to_component(origin.clone()))),
716 |prev_key, dup_value| {
717 errors.push(
718 dup_value.location(),
719 BuildError::InterfaceFieldNameCollision {
720 name_at_previous_location: prev_key.clone(),
721 type_name: extension.name.clone(),
722 },
723 )
724 },
725 );
726 }
727}
728
729impl UnionType {
730 fn from_ast(
731 errors: &mut DiagnosticList,
732 definition: &Node<ast::UnionTypeDefinition>,
733 extensions: Vec<ast::Definition>,
734 ) -> Node<Self> {
735 let mut ty = Self {
736 description: definition.description.clone(),
737 name: definition.name.clone(),
738 directives: definition
739 .directives
740 .iter()
741 .map(|d| d.to_component(ComponentOrigin::Definition))
742 .collect(),
743 members: collect_sticky_set(
744 definition
745 .members
746 .iter()
747 .map(|name| name.to_component(ComponentOrigin::Definition)),
748 |prev, dup| {
749 errors.push(
750 dup.location(),
751 BuildError::UnionMemberNameCollision {
752 name_at_previous_location: prev.name.clone(),
753 type_name: definition.name.clone(),
754 },
755 )
756 },
757 ),
758 };
759 for def in &extensions {
760 if let ast::Definition::UnionTypeExtension(ext) = def {
761 ty.extend_ast(errors, ext)
762 }
763 }
764 definition.same_location(ty)
765 }
766
767 fn extend_ast(
768 &mut self,
769 errors: &mut DiagnosticList,
770 extension: &Node<ast::UnionTypeExtension>,
771 ) {
772 let origin = ComponentOrigin::Extension(ExtensionId::new(extension));
773 self.directives.extend(
774 extension
775 .directives
776 .iter()
777 .map(|d| d.to_component(origin.clone())),
778 );
779 extend_sticky_set(
780 &mut self.members,
781 extension
782 .members
783 .iter()
784 .map(|name| name.to_component(origin.clone())),
785 |prev, dup| {
786 errors.push(
787 dup.location(),
788 BuildError::UnionMemberNameCollision {
789 name_at_previous_location: prev.name.clone(),
790 type_name: extension.name.clone(),
791 },
792 )
793 },
794 );
795 }
796}
797
798impl EnumType {
799 fn from_ast(
800 errors: &mut DiagnosticList,
801 definition: &Node<ast::EnumTypeDefinition>,
802 extensions: Vec<ast::Definition>,
803 ) -> Node<Self> {
804 let mut ty = Self {
805 description: definition.description.clone(),
806 name: definition.name.clone(),
807 directives: definition
808 .directives
809 .iter()
810 .map(|d| d.to_component(ComponentOrigin::Definition))
811 .collect(),
812 values: collect_sticky(
813 definition.values.iter().map(|value_def| {
814 (
815 &value_def.value,
816 value_def.to_component(ComponentOrigin::Definition),
817 )
818 }),
819 |prev_key, dup_value| {
820 errors.push(
821 dup_value.location(),
822 BuildError::EnumValueNameCollision {
823 name_at_previous_location: prev_key.clone(),
824 type_name: definition.name.clone(),
825 },
826 )
827 },
828 ),
829 };
830 for def in &extensions {
831 if let ast::Definition::EnumTypeExtension(ext) = def {
832 ty.extend_ast(errors, ext)
833 }
834 }
835 definition.same_location(ty)
836 }
837
838 fn extend_ast(
839 &mut self,
840 errors: &mut DiagnosticList,
841 extension: &Node<ast::EnumTypeExtension>,
842 ) {
843 let origin = ComponentOrigin::Extension(ExtensionId::new(extension));
844 self.directives.extend(
845 extension
846 .directives
847 .iter()
848 .map(|d| d.to_component(origin.clone())),
849 );
850 extend_sticky(
851 &mut self.values,
852 extension
853 .values
854 .iter()
855 .map(|value_def| (&value_def.value, value_def.to_component(origin.clone()))),
856 |prev_key, dup_value| {
857 errors.push(
858 dup_value.location(),
859 BuildError::EnumValueNameCollision {
860 name_at_previous_location: prev_key.clone(),
861 type_name: extension.name.clone(),
862 },
863 )
864 },
865 )
866 }
867}
868
869impl InputObjectType {
870 fn from_ast(
871 errors: &mut DiagnosticList,
872 definition: &Node<ast::InputObjectTypeDefinition>,
873 extensions: Vec<ast::Definition>,
874 ) -> Node<Self> {
875 let mut ty = Self {
876 description: definition.description.clone(),
877 name: definition.name.clone(),
878 directives: definition
879 .directives
880 .iter()
881 .map(|d| d.to_component(ComponentOrigin::Definition))
882 .collect(),
883 fields: collect_sticky(
884 definition
885 .fields
886 .iter()
887 .map(|field| (&field.name, field.to_component(ComponentOrigin::Definition))),
888 |prev_key, dup_value| {
889 errors.push(
890 dup_value.location(),
891 BuildError::InputFieldNameCollision {
892 name_at_previous_location: prev_key.clone(),
893 type_name: definition.name.clone(),
894 },
895 )
896 },
897 ),
898 };
899 for def in &extensions {
900 if let ast::Definition::InputObjectTypeExtension(ext) = def {
901 ty.extend_ast(errors, ext)
902 }
903 }
904 definition.same_location(ty)
905 }
906
907 fn extend_ast(
908 &mut self,
909 errors: &mut DiagnosticList,
910 extension: &Node<ast::InputObjectTypeExtension>,
911 ) {
912 let origin = ComponentOrigin::Extension(ExtensionId::new(extension));
913 self.directives.extend(
914 extension
915 .directives
916 .iter()
917 .map(|d| d.to_component(origin.clone())),
918 );
919 extend_sticky(
920 &mut self.fields,
921 extension
922 .fields
923 .iter()
924 .map(|field| (&field.name, field.to_component(origin.clone()))),
925 |prev_key, dup_value| {
926 errors.push(
927 dup_value.location(),
928 BuildError::InputFieldNameCollision {
929 name_at_previous_location: prev_key.clone(),
930 type_name: extension.name.clone(),
931 },
932 )
933 },
934 )
935 }
936}
937
938fn extend_sticky<'a, V>(
942 map: &mut IndexMap<Name, V>,
943 iter: impl IntoIterator<Item = (&'a Name, V)>,
944 mut duplicate: impl FnMut(&Name, V),
945) {
946 for (key, value) in iter.into_iter() {
947 match map.get_key_value(key) {
948 None => {
949 map.insert(key.clone(), value);
950 }
951 Some((prev_key, _)) => duplicate(prev_key, value),
952 }
953 }
954}
955
956fn collect_sticky<'a, V>(
960 iter: impl IntoIterator<Item = (&'a Name, V)>,
961 duplicate: impl FnMut(&Name, V),
962) -> IndexMap<Name, V> {
963 let mut map = IndexMap::with_hasher(Default::default());
964 extend_sticky(&mut map, iter, duplicate);
965 map
966}
967
968fn extend_sticky_set(
969 set: &mut IndexSet<ComponentName>,
970 iter: impl IntoIterator<Item = ComponentName>,
971 mut duplicate: impl FnMut(&ComponentName, ComponentName),
972) {
973 for value in iter.into_iter() {
974 match set.get(&value) {
975 None => {
976 set.insert(value);
977 }
978 Some(previous) => duplicate(previous, value),
979 }
980 }
981}
982fn collect_sticky_set(
983 iter: impl IntoIterator<Item = ComponentName>,
984 duplicate: impl FnMut(&ComponentName, ComponentName),
985) -> IndexSet<ComponentName> {
986 let mut set = IndexSet::with_hasher(Default::default());
987 extend_sticky_set(&mut set, iter, duplicate);
988 set
989}