@apollo/federation
Version:
Apollo Federation Utilities
95 lines • 5.66 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.externalUnused = void 0;
const graphql_1 = require("graphql");
const utils_1 = require("../../utils");
const externalUnused = ({ schema }) => {
const errors = [];
const types = schema.getTypeMap();
for (const [parentTypeName, parentType] of Object.entries(types)) {
if (!(0, graphql_1.isObjectType)(parentType))
continue;
const typeFederationMetadata = (0, utils_1.getFederationMetadata)(parentType);
if (typeFederationMetadata) {
const { serviceName, keys } = typeFederationMetadata;
if (serviceName && keys && !keys[serviceName])
continue;
}
if (typeFederationMetadata === null || typeFederationMetadata === void 0 ? void 0 : typeFederationMetadata.externals) {
for (const [serviceName, externalFieldsForService] of Object.entries(typeFederationMetadata.externals)) {
for (const { field: externalField } of externalFieldsForService) {
const externalFieldName = externalField.name.value;
const hasMatchingKeyOnType = Boolean((0, utils_1.hasMatchingFieldInDirectives)({
directives: (0, utils_1.findDirectivesOnNode)(parentType.astNode, 'key'),
fieldNameToMatch: externalFieldName,
namedType: parentType,
}));
if (hasMatchingKeyOnType)
continue;
const hasMatchingProvidesOnAnotherType = (0, utils_1.findFieldsThatReturnType)({
schema,
typeToFind: parentType,
}).some(field => (0, utils_1.findDirectivesOnNode)(field.astNode, 'provides').some(directive => {
if (!directive.arguments)
return false;
const selections = (0, utils_1.isStringValueNode)(directive.arguments[0].value) &&
(0, utils_1.parseFieldSet)(directive.arguments[0].value.value);
return (selections &&
selections.some(selection => selection.kind === graphql_1.Kind.FIELD &&
selection.name.value === externalFieldName));
}));
if (hasMatchingProvidesOnAnotherType)
continue;
const hasMatchingRequiresOnAnotherType = Object.values(schema.getTypeMap()).some(namedType => {
if (!(0, graphql_1.isObjectType)(namedType))
return false;
return Object.values(namedType.getFields()).some(field => (0, utils_1.findDirectivesOnNode)(field.astNode, 'requires').some(directive => {
if (!directive.arguments)
return false;
const selections = (0, utils_1.isStringValueNode)(directive.arguments[0].value) &&
(0, utils_1.parseFieldSet)(directive.arguments[0].value.value);
if (!selections)
return false;
return (0, utils_1.selectionIncludesField)({
selections,
selectionSetType: namedType,
typeToFind: parentType,
fieldToFind: externalFieldName,
});
}));
});
if (hasMatchingRequiresOnAnotherType)
continue;
const hasMatchingRequiresOnType = Object.values(parentType.getFields()).some(maybeRequiresField => {
var _a;
const fieldOwner = (_a = (0, utils_1.getFederationMetadata)(maybeRequiresField)) === null || _a === void 0 ? void 0 : _a.serviceName;
if (fieldOwner !== serviceName)
return false;
const requiresDirectives = (0, utils_1.findDirectivesOnNode)(maybeRequiresField.astNode, 'requires');
return (0, utils_1.hasMatchingFieldInDirectives)({
directives: requiresDirectives,
fieldNameToMatch: externalFieldName,
namedType: parentType,
});
});
if (hasMatchingRequiresOnType)
continue;
const fieldsOnInterfacesImplementedByParentType = new Set();
for (const _interface of parentType.getInterfaces()) {
for (const fieldName in _interface.getFields()) {
fieldsOnInterfacesImplementedByParentType.add(fieldName);
}
}
if (fieldsOnInterfacesImplementedByParentType.has(externalFieldName)) {
continue;
}
errors.push((0, utils_1.errorWithCode)('EXTERNAL_UNUSED', (0, utils_1.logServiceAndType)(serviceName, parentTypeName, externalFieldName) +
`is marked as @external but is not used by a @requires, @key, or @provides directive.`, (0, utils_1.findDirectivesOnNode)(externalField, 'external')));
}
}
}
}
return errors;
};
exports.externalUnused = externalUnused;
//# sourceMappingURL=externalUnused.js.map
;