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