pushParentDefinitionDataToDocumentDefinitions()

in composition/src/v1/federation/federation-factory.ts [1794:2021]


  pushParentDefinitionDataToDocumentDefinitions(interfaceImplementations: InterfaceImplementationData[]) {
    for (const [parentTypeName, parentDefinitionData] of this.parentDefinitionDataByTypeName) {
      if (parentDefinitionData.extensionType !== ExtensionType.NONE) {
        this.errors.push(
          noBaseDefinitionForExtensionError(kindToTypeString(parentDefinitionData.kind), parentTypeName),
        );
      }
      switch (parentDefinitionData.kind) {
        case Kind.ENUM_TYPE_DEFINITION:
          const enumValueNodes: Array<MutableEnumValueNode> = [];
          const clientEnumValueNodes: Array<MutableEnumValueNode> = [];
          const mergeMethod = this.getEnumValueMergeMethod(parentTypeName);
          for (const enumValueData of parentDefinitionData.enumValueDataByValueName.values()) {
            const enumValueNode = getNodeForRouterSchemaByData(
              enumValueData,
              this.persistedDirectiveDefinitionByDirectiveName,
              this.errors,
            );
            const isValueInaccessible = isNodeDataInaccessible(enumValueData);
            const clientEnumValueNode: MutableEnumValueNode = {
              ...enumValueData.node,
              directives: getClientPersistedDirectiveNodes(enumValueData),
            };
            switch (mergeMethod) {
              case MergeMethod.CONSISTENT:
                if (!isValueInaccessible && parentDefinitionData.appearances > enumValueData.appearances) {
                  this.errors.push(incompatibleSharedEnumError(parentTypeName));
                }
                enumValueNodes.push(enumValueNode);
                if (!isValueInaccessible) {
                  clientEnumValueNodes.push(clientEnumValueNode);
                }
                break;
              case MergeMethod.INTERSECTION:
                if (parentDefinitionData.appearances === enumValueData.appearances) {
                  enumValueNodes.push(enumValueNode);
                  if (!isValueInaccessible) {
                    clientEnumValueNodes.push(clientEnumValueNode);
                  }
                }
                break;
              default:
                enumValueNodes.push(enumValueNode);
                if (!isValueInaccessible) {
                  clientEnumValueNodes.push(clientEnumValueNode);
                }
                break;
            }
          }
          parentDefinitionData.node.values = enumValueNodes;
          this.routerDefinitions.push(this.getNodeForRouterSchemaByData(parentDefinitionData));
          if (isNodeDataInaccessible(parentDefinitionData)) {
            this.validateReferencesOfInaccessibleType(parentDefinitionData);
            this.internalGraph.setNodeInaccessible(parentDefinitionData.name);
            break;
          }
          if (clientEnumValueNodes.length < 1) {
            this.errors.push(
              allChildDefinitionsAreInaccessibleError(
                kindToTypeString(parentDefinitionData.kind),
                parentTypeName,
                ENUM_VALUE,
              ),
            );
            break;
          }
          this.clientDefinitions.push({
            ...parentDefinitionData.node,
            directives: getClientPersistedDirectiveNodes(parentDefinitionData),
            values: clientEnumValueNodes,
          });
          break;
        case Kind.INPUT_OBJECT_TYPE_DEFINITION:
          const invalidRequiredInputs: Array<InvalidRequiredInputValueData> = [];
          const inputValueNodes: Array<MutableInputValueNode> = [];
          const clientInputValueNodes: Array<MutableInputValueNode> = [];
          for (const [inputValueName, inputValueData] of parentDefinitionData.inputValueDataByValueName) {
            if (parentDefinitionData.subgraphNames.size === inputValueData.subgraphNames.size) {
              inputValueNodes.push(this.getNodeWithPersistedDirectivesByInputValueData(inputValueData));
              if (isNodeDataInaccessible(inputValueData)) {
                continue;
              }
              clientInputValueNodes.push({
                ...inputValueData.node,
                directives: getClientPersistedDirectiveNodes(inputValueData),
              });
            } else if (isTypeRequired(inputValueData.type)) {
              invalidRequiredInputs.push({
                inputValueName,
                missingSubgraphs: getEntriesNotInHashSet(
                  parentDefinitionData.subgraphNames,
                  inputValueData.subgraphNames,
                ),
                requiredSubgraphs: [...inputValueData.requiredSubgraphNames],
              });
            }
          }
          if (invalidRequiredInputs.length > 0) {
            this.errors.push(
              invalidRequiredInputValueError(INPUT_OBJECT, parentTypeName, invalidRequiredInputs, false),
            );
            break;
          }
          parentDefinitionData.node.fields = inputValueNodes;
          this.routerDefinitions.push(this.getNodeForRouterSchemaByData(parentDefinitionData));
          if (isNodeDataInaccessible(parentDefinitionData)) {
            this.validateReferencesOfInaccessibleType(parentDefinitionData);
            break;
          }
          if (clientInputValueNodes.length < 1) {
            this.errors.push(
              allChildDefinitionsAreInaccessibleError(
                kindToTypeString(parentDefinitionData.kind),
                parentTypeName,
                'input field',
              ),
            );
            break;
          }
          this.clientDefinitions.push({
            ...parentDefinitionData.node,
            directives: getClientPersistedDirectiveNodes(parentDefinitionData),
            fields: clientInputValueNodes,
          });
          break;
        case Kind.INTERFACE_TYPE_DEFINITION:
        // intentional fallthrough
        case Kind.OBJECT_TYPE_DEFINITION:
          const fieldNodes: Array<MutableFieldNode> = [];
          const clientSchemaFieldNodes: Array<MutableFieldNode> = [];
          const graphFieldDataByFieldName = new Map<string, GraphFieldData>();
          const invalidFieldNames = newInvalidFieldNames();
          const isObject = parentDefinitionData.kind === Kind.OBJECT_TYPE_DEFINITION;
          for (const [fieldName, fieldData] of parentDefinitionData.fieldDataByFieldName) {
            pushAuthorizationDirectives(fieldData, this.authorizationDataByParentTypeName.get(parentTypeName));
            const argumentNodes = this.getValidFieldArgumentNodes(fieldData);
            if (isObject) {
              validateExternalAndShareable(fieldData, invalidFieldNames);
            }
            fieldNodes.push(this.getNodeWithPersistedDirectivesByFieldData(fieldData, argumentNodes));
            if (isNodeDataInaccessible(fieldData)) {
              continue;
            }
            clientSchemaFieldNodes.push(getClientSchemaFieldNodeByFieldData(fieldData));
            graphFieldDataByFieldName.set(fieldName, this.fieldDataToGraphFieldData(fieldData));
          }
          if (isObject) {
            if (invalidFieldNames.byShareable.size > 0) {
              this.errors.push(invalidFieldShareabilityError(parentDefinitionData, invalidFieldNames.byShareable));
            }
            if (invalidFieldNames.subgraphNamesByExternalFieldName.size > 0) {
              this.errors.push(
                allExternalFieldInstancesError(parentTypeName, invalidFieldNames.subgraphNamesByExternalFieldName),
              );
            }
          }
          parentDefinitionData.node.fields = fieldNodes;
          this.internalGraph.initializeNode(parentTypeName, graphFieldDataByFieldName);
          // Implemented interfaces can only be validated after all fields are merged
          if (parentDefinitionData.implementedInterfaceTypeNames.size > 0) {
            interfaceImplementations.push({ data: parentDefinitionData, clientSchemaFieldNodes });
            break;
          }
          this.routerDefinitions.push(this.getNodeForRouterSchemaByData(parentDefinitionData));
          const isQuery = isNodeQuery(parentTypeName);
          if (isNodeDataInaccessible(parentDefinitionData)) {
            if (isQuery) {
              this.errors.push(inaccessibleQueryRootTypeError);
              break;
            }
            this.validateReferencesOfInaccessibleType(parentDefinitionData);
            this.internalGraph.setNodeInaccessible(parentDefinitionData.name);
            break;
          }
          if (clientSchemaFieldNodes.length < 1) {
            const error = isQuery
              ? noQueryRootTypeError(false)
              : allChildDefinitionsAreInaccessibleError(
                  kindToTypeString(parentDefinitionData.kind),
                  parentTypeName,
                  FIELD,
                );
            this.errors.push(error);
            break;
          }
          this.clientDefinitions.push({
            ...parentDefinitionData.node,
            directives: getClientPersistedDirectiveNodes(parentDefinitionData),
            fields: clientSchemaFieldNodes,
          });
          break;
        case Kind.SCALAR_TYPE_DEFINITION:
          if (BASE_SCALARS.has(parentTypeName)) {
            break;
          }
          this.routerDefinitions.push(this.getNodeForRouterSchemaByData(parentDefinitionData));
          if (isNodeDataInaccessible(parentDefinitionData)) {
            this.validateReferencesOfInaccessibleType(parentDefinitionData);
            this.internalGraph.setNodeInaccessible(parentDefinitionData.name);
            break;
          }
          this.clientDefinitions.push({
            ...parentDefinitionData.node,
            directives: getClientPersistedDirectiveNodes(parentDefinitionData),
          });
          break;
        case Kind.UNION_TYPE_DEFINITION:
          parentDefinitionData.node.types = mapToArrayOfValues(parentDefinitionData.memberByMemberTypeName);
          this.routerDefinitions.push(this.getNodeForRouterSchemaByData(parentDefinitionData));
          if (isNodeDataInaccessible(parentDefinitionData)) {
            this.validateReferencesOfInaccessibleType(parentDefinitionData);
            this.internalGraph.setNodeInaccessible(parentDefinitionData.name);
            break;
          }
          const clientMembers = this.getClientSchemaUnionMembers(parentDefinitionData);
          if (clientMembers.length < 1) {
            this.errors.push(allChildDefinitionsAreInaccessibleError(UNION, parentTypeName, 'union member type'));
            break;
          }
          this.clientDefinitions.push({
            ...parentDefinitionData.node,
            directives: getClientPersistedDirectiveNodes(parentDefinitionData),
            types: clientMembers,
          });
          break;
      }
    }
  }