UNPKG

@apollo/subgraph

Version:
187 lines 9.54 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.directiveDefinitionsAreCompatible = exports.typeIncludesDirective = exports.gatherDirectives = exports.isFederationDirective = exports.federationDirectives = exports.OverrideDirective = exports.InaccessibleDirective = exports.LinkDirective = exports.ShareableDirective = exports.TagDirective = exports.ProvidesDirective = exports.RequiresDirective = exports.ExternalDirective = exports.ExtendsDirective = exports.KeyDirective = void 0; const graphql_1 = require("graphql"); const types_1 = require("./types"); exports.KeyDirective = new graphql_1.GraphQLDirective({ name: 'key', description: 'Designates an object type as an entity and specifies its key fields. Key fields are a set of fields that a subgraph can use to uniquely identify any instance of the entity.', locations: [graphql_1.DirectiveLocation.OBJECT, graphql_1.DirectiveLocation.INTERFACE], isRepeatable: true, args: { fields: { type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLString), }, resolvable: { type: graphql_1.GraphQLBoolean, defaultValue: true } }, }); exports.ExtendsDirective = new graphql_1.GraphQLDirective({ name: 'extends', description: 'Indicates that an object or interface definition is an extension of another definition of that same type. This directive is for use with GraphQL subgraph libraries that do not support the extend keyword. Most commonly, these are subgraph libraries that generate their schema programmatically instead of using a static .graphql file.', locations: [graphql_1.DirectiveLocation.OBJECT, graphql_1.DirectiveLocation.INTERFACE], }); exports.ExternalDirective = new graphql_1.GraphQLDirective({ name: 'external', description: 'Indicates that this subgraph usually can\'t resolve a particular object field, but it still needs to define that field for other purposes. This directive is always used in combination with another directive that references object fields, such as @provides or @requires.', locations: [graphql_1.DirectiveLocation.OBJECT, graphql_1.DirectiveLocation.FIELD_DEFINITION], }); exports.RequiresDirective = new graphql_1.GraphQLDirective({ name: 'requires', description: 'Indicates that the resolver for a particular entity field depends on the values of other entity fields that are resolved by other subgraphs. This tells the router that it needs to fetch the values of those externally defined fields first, even if the original client query didn\'t request them.', locations: [graphql_1.DirectiveLocation.FIELD_DEFINITION], args: { fields: { type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLString), }, }, }); exports.ProvidesDirective = new graphql_1.GraphQLDirective({ name: 'provides', description: 'Specifies a set of entity fields that a subgraph can resolve, but only at a particular schema path (at other paths, the subgraph can\'t resolve those fields). If a subgraph can always resolve a particular entity field, do not apply this directive. Using this directive is always an optional optimization. It can reduce the total number of subgraphs that your router needs to communicate with to resolve certain operations, which can improve performance.', locations: [graphql_1.DirectiveLocation.FIELD_DEFINITION], args: { fields: { type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLString), }, }, }); exports.TagDirective = new graphql_1.GraphQLDirective({ name: 'tag', description: 'Applies arbitrary string metadata to a schema location. Custom tooling can use this metadata during any step of the schema delivery flow, including composition, static analysis, and documentation. The GraphOS Enterprise contracts feature uses @tag with its inclusion and exclusion filters.', locations: [ graphql_1.DirectiveLocation.FIELD_DEFINITION, graphql_1.DirectiveLocation.OBJECT, graphql_1.DirectiveLocation.INTERFACE, graphql_1.DirectiveLocation.UNION, graphql_1.DirectiveLocation.ARGUMENT_DEFINITION, graphql_1.DirectiveLocation.SCALAR, graphql_1.DirectiveLocation.ENUM, graphql_1.DirectiveLocation.ENUM_VALUE, graphql_1.DirectiveLocation.INPUT_OBJECT, graphql_1.DirectiveLocation.INPUT_FIELD_DEFINITION, graphql_1.DirectiveLocation.SCHEMA, ], isRepeatable: true, args: { name: { type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLString), }, }, }); exports.ShareableDirective = new graphql_1.GraphQLDirective({ name: 'shareable', description: 'Indicates that an object type\'s field is allowed to be resolved by multiple subgraphs (by default in Federation 2, object fields can be resolved by only one subgraph).', locations: [graphql_1.DirectiveLocation.FIELD_DEFINITION, graphql_1.DirectiveLocation.OBJECT], }); exports.LinkDirective = new graphql_1.GraphQLDirective({ name: 'link', description: 'This directive links definitions from an external specification to this schema.', locations: [graphql_1.DirectiveLocation.SCHEMA], args: { url: { type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLString), }, import: { type: new graphql_1.GraphQLList(types_1.LinkImportType), } }, }); exports.InaccessibleDirective = new graphql_1.GraphQLDirective({ name: 'inaccessible', description: 'Indicates that a definition in the subgraph schema should be omitted from the router\'s API schema, even if that definition is also present in other subgraphs. This means that the field is not exposed to clients at all.', locations: [ graphql_1.DirectiveLocation.FIELD_DEFINITION, graphql_1.DirectiveLocation.OBJECT, graphql_1.DirectiveLocation.INTERFACE, graphql_1.DirectiveLocation.UNION, graphql_1.DirectiveLocation.ARGUMENT_DEFINITION, graphql_1.DirectiveLocation.SCALAR, graphql_1.DirectiveLocation.ENUM, graphql_1.DirectiveLocation.ENUM_VALUE, graphql_1.DirectiveLocation.INPUT_OBJECT, graphql_1.DirectiveLocation.INPUT_FIELD_DEFINITION, ], }); exports.OverrideDirective = new graphql_1.GraphQLDirective({ name: 'override', description: 'Indicates that an object field is now resolved by this subgraph instead of another subgraph where it\'s also defined. This enables you to migrate a field from one subgraph to another.', locations: [graphql_1.DirectiveLocation.FIELD_DEFINITION], args: { from: { type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLString), }, label: { type: graphql_1.GraphQLString, } }, }); exports.federationDirectives = [ exports.KeyDirective, exports.ExtendsDirective, exports.ExternalDirective, exports.RequiresDirective, exports.ProvidesDirective, exports.ShareableDirective, exports.LinkDirective, exports.TagDirective, exports.InaccessibleDirective, exports.OverrideDirective, ]; function isFederationDirective(directive) { return exports.federationDirectives.some(({ name }) => name === directive.name); } exports.isFederationDirective = isFederationDirective; function hasDirectives(node) { return Boolean('directives' in node && node.directives); } function gatherDirectives(element) { const directives = []; if ('extensionASTNodes' in element && element.extensionASTNodes) { for (const node of element.extensionASTNodes) { if (hasDirectives(node)) { directives.push(...node.directives); } } } if (element.astNode && hasDirectives(element.astNode)) directives.push(...element.astNode.directives); return directives; } exports.gatherDirectives = gatherDirectives; function typeIncludesDirective(type, directiveName) { const directives = gatherDirectives(type); return directives.some((directive) => directive.name.value === directiveName); } exports.typeIncludesDirective = typeIncludesDirective; function directiveDefinitionsAreCompatible(baseDefinition, toCompare) { var _a, _b, _c, _d; if (baseDefinition.name.value !== toCompare.name.value) return false; if (((_a = baseDefinition.arguments) === null || _a === void 0 ? void 0 : _a.length) !== ((_b = toCompare.arguments) === null || _b === void 0 ? void 0 : _b.length)) { return false; } for (const arg of (_c = baseDefinition.arguments) !== null && _c !== void 0 ? _c : []) { const toCompareArg = (_d = toCompare.arguments) === null || _d === void 0 ? void 0 : _d.find((a) => a.name.value === arg.name.value); if (!toCompareArg) return false; if ((0, graphql_1.print)(stripDescriptions(arg)) !== (0, graphql_1.print)(stripDescriptions(toCompareArg))) { return false; } } if (toCompare.locations.some((location) => !baseDefinition.locations.find((baseLocation) => baseLocation.value === location.value))) { return false; } return true; } exports.directiveDefinitionsAreCompatible = directiveDefinitionsAreCompatible; function stripDescriptions(astNode) { return (0, graphql_1.visit)(astNode, { enter(node) { return 'description' in node ? { ...node, description: undefined } : node; }, }); } //# sourceMappingURL=directives.js.map