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 pub fn iter_orphan_extension_types(&self) -> impl Iterator<Item = &Name> {
272 self.orphan_type_extensions.keys()
273 }
274
275 #[allow(clippy::result_large_err)] pub fn build(self) -> Result<Schema, WithErrors<Schema>> {
278 let (schema, errors) = self.build_inner();
279 errors.into_result_with(schema)
280 }
281
282 pub(crate) fn build_inner(self) -> (Schema, DiagnosticList) {
283 let SchemaBuilder {
284 adopt_orphan_extensions,
285 ignore_builtin_redefinitions: _allow_builtin_redefinitions,
286 mut schema,
287 schema_definition,
288 orphan_type_extensions,
289 mut errors,
290 } = self;
291 schema.sources = errors.sources.clone();
292
293 if adopt_orphan_extensions {
296 for (type_name, extensions) in orphan_type_extensions {
297 let type_def = adopt_type_extensions(&mut errors, &type_name, &extensions);
298 let previous = schema.types.insert(type_name, type_def);
299 assert!(previous.is_none());
300 }
301 } else {
302 for extensions in orphan_type_extensions.values() {
303 for ext in extensions {
304 let name = ext.name().unwrap().clone();
305 errors.push(name.location(), BuildError::OrphanTypeExtension { name })
306 }
307 }
308 }
309
310 match schema_definition {
311 SchemaDefinitionStatus::Found => {}
312 SchemaDefinitionStatus::NoneSoFar { orphan_extensions } => {
313 let schema_def = schema.schema_definition.make_mut();
315 if adopt_orphan_extensions {
316 for ext in &orphan_extensions {
320 schema_def.extend_ast(&mut errors, ext)
321 }
322 if schema_def.query.is_none()
323 && schema_def.mutation.is_none()
324 && schema_def.subscription.is_none()
325 {
326 add_implicit_root_types(schema_def, &schema.types);
327 }
328 } else {
329 let has_implicit_root_operation =
330 add_implicit_root_types(schema_def, &schema.types);
331 if has_implicit_root_operation {
332 for ext in &orphan_extensions {
338 schema_def.extend_ast(&mut errors, ext)
339 }
340 } else {
341 for ext in &orphan_extensions {
342 errors.push(ext.location(), BuildError::OrphanSchemaExtension)
343 }
344 }
345 }
346 }
347 }
348 (schema, errors)
349 }
350}
351
352fn add_implicit_root_types(
353 schema_def: &mut SchemaDefinition,
354 types: &IndexMap<Name, ExtendedType>,
355) -> bool {
356 let mut has_implicit_root_operation = false;
357 for (operation_type, root_operation) in [
358 (OperationType::Query, &mut schema_def.query),
359 (OperationType::Mutation, &mut schema_def.mutation),
360 (OperationType::Subscription, &mut schema_def.subscription),
361 ] {
362 let name = operation_type.default_type_name();
363 if types.get(&name).is_some_and(|def| def.is_object()) {
364 *root_operation = Some(name.into());
365 has_implicit_root_operation = true
366 }
367 }
368 has_implicit_root_operation
369}
370
371fn adopt_type_extensions(
372 errors: &mut DiagnosticList,
373 type_name: &Name,
374 extensions: &[ast::Definition],
375) -> ExtendedType {
376 macro_rules! extend {
377 ($( $ExtensionVariant: path => $describe: literal $empty_def: expr )+) => {
378 match &extensions[0] {
379 $(
380 $ExtensionVariant(_) => {
381 let mut def = $empty_def;
382 for ext in extensions {
383 if let $ExtensionVariant(ext) = ext {
384 def.extend_ast(errors, ext)
385 } else {
386 let ext_name = ext.name().unwrap();
387 errors.push(
388 ext_name.location(),
389 BuildError::TypeExtensionKindMismatch {
390 name: ext_name.clone(),
391 describe_ext: ext.describe(),
392 def_location: type_name.location(),
393 describe_def: $describe,
394 }
395 )
396 }
397 }
398 def.into()
399 }
400 )+
401 _ => unreachable!(),
402 }
403 };
404 }
405 let name = type_name.clone();
406 extend! {
407 ast::Definition::ScalarTypeExtension => "a scalar type" ScalarType {
408 description: Default::default(),
409 name,
410 directives: Default::default(),
411 }
412 ast::Definition::ObjectTypeExtension => "an object type" ObjectType {
413 description: Default::default(),
414 name,
415 implements_interfaces: Default::default(),
416 directives: Default::default(),
417 fields: Default::default(),
418 }
419 ast::Definition::InterfaceTypeExtension => "an interface type" InterfaceType {
420 description: Default::default(),
421 name,
422 implements_interfaces: Default::default(),
423 directives: Default::default(),
424 fields: Default::default(),
425 }
426 ast::Definition::UnionTypeExtension => "a union type" UnionType {
427 description: Default::default(),
428 name,
429 directives: Default::default(),
430 members: Default::default(),
431 }
432 ast::Definition::EnumTypeExtension => "an enum type" EnumType {
433 description: Default::default(),
434 name,
435 directives: Default::default(),
436 values: Default::default(),
437 }
438 ast::Definition::InputObjectTypeExtension => "an input object type" InputObjectType {
439 description: Default::default(),
440 name,
441 directives: Default::default(),
442 fields: Default::default(),
443 }
444 }
445}
446
447impl SchemaDefinition {
448 fn from_ast(
449 errors: &mut DiagnosticList,
450 definition: &Node<ast::SchemaDefinition>,
451 extensions: &[Node<ast::SchemaExtension>],
452 ) -> Node<Self> {
453 let mut root = Self {
454 description: definition.description.clone(),
455 directives: definition
456 .directives
457 .iter()
458 .map(|d| d.to_component(ComponentOrigin::Definition))
459 .collect(),
460 query: None,
461 mutation: None,
462 subscription: None,
463 };
464 root.add_root_operations(
465 errors,
466 ComponentOrigin::Definition,
467 &definition.root_operations,
468 );
469 for ext in extensions {
470 root.extend_ast(errors, ext)
471 }
472 definition.same_location(root)
473 }
474
475 fn extend_ast(&mut self, errors: &mut DiagnosticList, extension: &Node<ast::SchemaExtension>) {
476 let origin = ComponentOrigin::Extension(ExtensionId::new(extension));
477 self.directives.extend(
478 extension
479 .directives
480 .iter()
481 .map(|d| d.to_component(origin.clone())),
482 );
483 self.add_root_operations(errors, origin, &extension.root_operations)
484 }
485
486 fn add_root_operations(
487 &mut self,
488 errors: &mut DiagnosticList,
489 origin: ComponentOrigin,
490 root_operations: &[Node<(OperationType, Name)>],
491 ) {
492 for op in root_operations {
493 let (operation_type, object_type_name) = &**op;
494 let entry = match operation_type {
495 OperationType::Query => &mut self.query,
496 OperationType::Mutation => &mut self.mutation,
497 OperationType::Subscription => &mut self.subscription,
498 };
499 match entry {
500 None => *entry = Some(object_type_name.to_component(origin.clone())),
501 Some(previous) => errors.push(
502 op.location(),
503 BuildError::DuplicateRootOperation {
504 previous_location: previous.location(),
505 operation_type: operation_type.name(),
506 },
507 ),
508 }
509 }
510 }
511}
512
513impl ScalarType {
514 fn from_ast(
515 errors: &mut DiagnosticList,
516 definition: &Node<ast::ScalarTypeDefinition>,
517 extensions: Vec<ast::Definition>,
518 ) -> Node<Self> {
519 let mut ty = Self {
520 description: definition.description.clone(),
521 name: definition.name.clone(),
522 directives: definition
523 .directives
524 .iter()
525 .map(|d| d.to_component(ComponentOrigin::Definition))
526 .collect(),
527 };
528 for def in &extensions {
529 if let ast::Definition::ScalarTypeExtension(ext) = def {
530 ty.extend_ast(errors, ext)
531 }
532 }
533 definition.same_location(ty)
534 }
535
536 fn extend_ast(
537 &mut self,
538 _errors: &mut DiagnosticList,
539 extension: &Node<ast::ScalarTypeExtension>,
540 ) {
541 let origin = ComponentOrigin::Extension(ExtensionId::new(extension));
542 self.directives.extend(
543 extension
544 .directives
545 .iter()
546 .map(|d| d.to_component(origin.clone())),
547 );
548 }
549}
550
551impl ObjectType {
552 fn from_ast(
553 errors: &mut DiagnosticList,
554 definition: &Node<ast::ObjectTypeDefinition>,
555 extensions: Vec<ast::Definition>,
556 ) -> Node<Self> {
557 let mut ty = Self {
558 description: definition.description.clone(),
559 name: definition.name.clone(),
560 implements_interfaces: collect_sticky_set(
561 definition
562 .implements_interfaces
563 .iter()
564 .map(|name| name.to_component(ComponentOrigin::Definition)),
565 |prev, dup| {
566 errors.push(
567 dup.location(),
568 BuildError::DuplicateImplementsInterfaceInObject {
569 name_at_previous_location: prev.name.clone(),
570 type_name: definition.name.clone(),
571 },
572 )
573 },
574 ),
575 directives: definition
576 .directives
577 .iter()
578 .map(|d| d.to_component(ComponentOrigin::Definition))
579 .collect(),
580 fields: collect_sticky(
581 definition
582 .fields
583 .iter()
584 .map(|field| (&field.name, field.to_component(ComponentOrigin::Definition))),
585 |prev_key, dup_value| {
586 errors.push(
587 dup_value.location(),
588 BuildError::ObjectFieldNameCollision {
589 name_at_previous_location: prev_key.clone(),
590 type_name: definition.name.clone(),
591 },
592 )
593 },
594 ),
595 };
596 for def in &extensions {
597 if let ast::Definition::ObjectTypeExtension(ext) = def {
598 ty.extend_ast(errors, ext)
599 }
600 }
601 definition.same_location(ty)
602 }
603
604 fn extend_ast(
605 &mut self,
606 errors: &mut DiagnosticList,
607 extension: &Node<ast::ObjectTypeExtension>,
608 ) {
609 let origin = ComponentOrigin::Extension(ExtensionId::new(extension));
610 self.directives.extend(
611 extension
612 .directives
613 .iter()
614 .map(|d| d.to_component(origin.clone())),
615 );
616 extend_sticky_set(
617 &mut self.implements_interfaces,
618 extension
619 .implements_interfaces
620 .iter()
621 .map(|name| name.to_component(origin.clone())),
622 |prev, dup| {
623 errors.push(
624 dup.location(),
625 BuildError::DuplicateImplementsInterfaceInObject {
626 name_at_previous_location: prev.name.clone(),
627 type_name: extension.name.clone(),
628 },
629 )
630 },
631 );
632 extend_sticky(
633 &mut self.fields,
634 extension
635 .fields
636 .iter()
637 .map(|field| (&field.name, field.to_component(origin.clone()))),
638 |prev_key, dup_value| {
639 errors.push(
640 dup_value.location(),
641 BuildError::ObjectFieldNameCollision {
642 name_at_previous_location: prev_key.clone(),
643 type_name: extension.name.clone(),
644 },
645 )
646 },
647 );
648 }
649}
650
651impl InterfaceType {
652 fn from_ast(
653 errors: &mut DiagnosticList,
654 definition: &Node<ast::InterfaceTypeDefinition>,
655 extensions: Vec<ast::Definition>,
656 ) -> Node<Self> {
657 let mut ty = Self {
658 description: definition.description.clone(),
659 name: definition.name.clone(),
660 implements_interfaces: collect_sticky_set(
661 definition
662 .implements_interfaces
663 .iter()
664 .map(|name| name.to_component(ComponentOrigin::Definition)),
665 |prev, dup| {
666 errors.push(
667 dup.location(),
668 BuildError::DuplicateImplementsInterfaceInInterface {
669 name_at_previous_location: prev.name.clone(),
670 type_name: definition.name.clone(),
671 },
672 )
673 },
674 ),
675 directives: definition
676 .directives
677 .iter()
678 .map(|d| d.to_component(ComponentOrigin::Definition))
679 .collect(),
680 fields: collect_sticky(
681 definition
682 .fields
683 .iter()
684 .map(|field| (&field.name, field.to_component(ComponentOrigin::Definition))),
685 |prev_key, dup_value| {
686 errors.push(
687 dup_value.location(),
688 BuildError::InterfaceFieldNameCollision {
689 name_at_previous_location: prev_key.clone(),
690 type_name: definition.name.clone(),
691 },
692 )
693 },
694 ),
695 };
696 for def in &extensions {
697 if let ast::Definition::InterfaceTypeExtension(ext) = def {
698 ty.extend_ast(errors, ext)
699 }
700 }
701 definition.same_location(ty)
702 }
703
704 fn extend_ast(
705 &mut self,
706 errors: &mut DiagnosticList,
707 extension: &Node<ast::InterfaceTypeExtension>,
708 ) {
709 let origin = ComponentOrigin::Extension(ExtensionId::new(extension));
710 self.directives.extend(
711 extension
712 .directives
713 .iter()
714 .map(|d| d.to_component(origin.clone())),
715 );
716 extend_sticky_set(
717 &mut self.implements_interfaces,
718 extension
719 .implements_interfaces
720 .iter()
721 .map(|name| name.to_component(origin.clone())),
722 |prev, dup| {
723 errors.push(
724 dup.location(),
725 BuildError::DuplicateImplementsInterfaceInInterface {
726 name_at_previous_location: prev.name.clone(),
727 type_name: extension.name.clone(),
728 },
729 )
730 },
731 );
732 extend_sticky(
733 &mut self.fields,
734 extension
735 .fields
736 .iter()
737 .map(|field| (&field.name, field.to_component(origin.clone()))),
738 |prev_key, dup_value| {
739 errors.push(
740 dup_value.location(),
741 BuildError::InterfaceFieldNameCollision {
742 name_at_previous_location: prev_key.clone(),
743 type_name: extension.name.clone(),
744 },
745 )
746 },
747 );
748 }
749}
750
751impl UnionType {
752 fn from_ast(
753 errors: &mut DiagnosticList,
754 definition: &Node<ast::UnionTypeDefinition>,
755 extensions: Vec<ast::Definition>,
756 ) -> Node<Self> {
757 let mut ty = Self {
758 description: definition.description.clone(),
759 name: definition.name.clone(),
760 directives: definition
761 .directives
762 .iter()
763 .map(|d| d.to_component(ComponentOrigin::Definition))
764 .collect(),
765 members: collect_sticky_set(
766 definition
767 .members
768 .iter()
769 .map(|name| name.to_component(ComponentOrigin::Definition)),
770 |prev, dup| {
771 errors.push(
772 dup.location(),
773 BuildError::UnionMemberNameCollision {
774 name_at_previous_location: prev.name.clone(),
775 type_name: definition.name.clone(),
776 },
777 )
778 },
779 ),
780 };
781 for def in &extensions {
782 if let ast::Definition::UnionTypeExtension(ext) = def {
783 ty.extend_ast(errors, ext)
784 }
785 }
786 definition.same_location(ty)
787 }
788
789 fn extend_ast(
790 &mut self,
791 errors: &mut DiagnosticList,
792 extension: &Node<ast::UnionTypeExtension>,
793 ) {
794 let origin = ComponentOrigin::Extension(ExtensionId::new(extension));
795 self.directives.extend(
796 extension
797 .directives
798 .iter()
799 .map(|d| d.to_component(origin.clone())),
800 );
801 extend_sticky_set(
802 &mut self.members,
803 extension
804 .members
805 .iter()
806 .map(|name| name.to_component(origin.clone())),
807 |prev, dup| {
808 errors.push(
809 dup.location(),
810 BuildError::UnionMemberNameCollision {
811 name_at_previous_location: prev.name.clone(),
812 type_name: extension.name.clone(),
813 },
814 )
815 },
816 );
817 }
818}
819
820impl EnumType {
821 fn from_ast(
822 errors: &mut DiagnosticList,
823 definition: &Node<ast::EnumTypeDefinition>,
824 extensions: Vec<ast::Definition>,
825 ) -> Node<Self> {
826 let mut ty = Self {
827 description: definition.description.clone(),
828 name: definition.name.clone(),
829 directives: definition
830 .directives
831 .iter()
832 .map(|d| d.to_component(ComponentOrigin::Definition))
833 .collect(),
834 values: collect_sticky(
835 definition.values.iter().map(|value_def| {
836 (
837 &value_def.value,
838 value_def.to_component(ComponentOrigin::Definition),
839 )
840 }),
841 |prev_key, dup_value| {
842 errors.push(
843 dup_value.location(),
844 BuildError::EnumValueNameCollision {
845 name_at_previous_location: prev_key.clone(),
846 type_name: definition.name.clone(),
847 },
848 )
849 },
850 ),
851 };
852 for def in &extensions {
853 if let ast::Definition::EnumTypeExtension(ext) = def {
854 ty.extend_ast(errors, ext)
855 }
856 }
857 definition.same_location(ty)
858 }
859
860 fn extend_ast(
861 &mut self,
862 errors: &mut DiagnosticList,
863 extension: &Node<ast::EnumTypeExtension>,
864 ) {
865 let origin = ComponentOrigin::Extension(ExtensionId::new(extension));
866 self.directives.extend(
867 extension
868 .directives
869 .iter()
870 .map(|d| d.to_component(origin.clone())),
871 );
872 extend_sticky(
873 &mut self.values,
874 extension
875 .values
876 .iter()
877 .map(|value_def| (&value_def.value, value_def.to_component(origin.clone()))),
878 |prev_key, dup_value| {
879 errors.push(
880 dup_value.location(),
881 BuildError::EnumValueNameCollision {
882 name_at_previous_location: prev_key.clone(),
883 type_name: extension.name.clone(),
884 },
885 )
886 },
887 )
888 }
889}
890
891impl InputObjectType {
892 fn from_ast(
893 errors: &mut DiagnosticList,
894 definition: &Node<ast::InputObjectTypeDefinition>,
895 extensions: Vec<ast::Definition>,
896 ) -> Node<Self> {
897 let mut ty = Self {
898 description: definition.description.clone(),
899 name: definition.name.clone(),
900 directives: definition
901 .directives
902 .iter()
903 .map(|d| d.to_component(ComponentOrigin::Definition))
904 .collect(),
905 fields: collect_sticky(
906 definition
907 .fields
908 .iter()
909 .map(|field| (&field.name, field.to_component(ComponentOrigin::Definition))),
910 |prev_key, dup_value| {
911 errors.push(
912 dup_value.location(),
913 BuildError::InputFieldNameCollision {
914 name_at_previous_location: prev_key.clone(),
915 type_name: definition.name.clone(),
916 },
917 )
918 },
919 ),
920 };
921 for def in &extensions {
922 if let ast::Definition::InputObjectTypeExtension(ext) = def {
923 ty.extend_ast(errors, ext)
924 }
925 }
926 definition.same_location(ty)
927 }
928
929 fn extend_ast(
930 &mut self,
931 errors: &mut DiagnosticList,
932 extension: &Node<ast::InputObjectTypeExtension>,
933 ) {
934 let origin = ComponentOrigin::Extension(ExtensionId::new(extension));
935 self.directives.extend(
936 extension
937 .directives
938 .iter()
939 .map(|d| d.to_component(origin.clone())),
940 );
941 extend_sticky(
942 &mut self.fields,
943 extension
944 .fields
945 .iter()
946 .map(|field| (&field.name, field.to_component(origin.clone()))),
947 |prev_key, dup_value| {
948 errors.push(
949 dup_value.location(),
950 BuildError::InputFieldNameCollision {
951 name_at_previous_location: prev_key.clone(),
952 type_name: extension.name.clone(),
953 },
954 )
955 },
956 )
957 }
958}
959
960fn extend_sticky<'a, V>(
964 map: &mut IndexMap<Name, V>,
965 iter: impl IntoIterator<Item = (&'a Name, V)>,
966 mut duplicate: impl FnMut(&Name, V),
967) {
968 for (key, value) in iter.into_iter() {
969 match map.get_key_value(key) {
970 None => {
971 map.insert(key.clone(), value);
972 }
973 Some((prev_key, _)) => duplicate(prev_key, value),
974 }
975 }
976}
977
978fn collect_sticky<'a, V>(
982 iter: impl IntoIterator<Item = (&'a Name, V)>,
983 duplicate: impl FnMut(&Name, V),
984) -> IndexMap<Name, V> {
985 let mut map = IndexMap::with_hasher(Default::default());
986 extend_sticky(&mut map, iter, duplicate);
987 map
988}
989
990fn extend_sticky_set(
991 set: &mut IndexSet<ComponentName>,
992 iter: impl IntoIterator<Item = ComponentName>,
993 mut duplicate: impl FnMut(&ComponentName, ComponentName),
994) {
995 for value in iter.into_iter() {
996 match set.get(&value) {
997 None => {
998 set.insert(value);
999 }
1000 Some(previous) => duplicate(previous, value),
1001 }
1002 }
1003}
1004fn collect_sticky_set(
1005 iter: impl IntoIterator<Item = ComponentName>,
1006 duplicate: impl FnMut(&ComponentName, ComponentName),
1007) -> IndexSet<ComponentName> {
1008 let mut set = IndexSet::with_hasher(Default::default());
1009 extend_sticky_set(&mut set, iter, duplicate);
1010 set
1011}