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