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;
}
}
}