UNPKG

@apollo/federation

Version:
95 lines 5.66 kB
"use strict"; 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