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