UNPKG

@theguild/federation-composition

Version:
975 lines (974 loc) 72 kB
import { Kind, OperationTypeNode, specifiedDirectives as specifiedDirectiveTypes, specifiedScalarTypes, } from 'graphql'; import { print } from '../graphql/printer.js'; import { isFederationLink } from '../specifications/federation.js'; import { printOutputType } from './helpers.js'; export var TypeKind; (function (TypeKind) { TypeKind["OBJECT"] = "OBJECT"; TypeKind["INTERFACE"] = "INTERFACE"; TypeKind["ENUM"] = "ENUM"; TypeKind["UNION"] = "UNION"; TypeKind["SCALAR"] = "SCALAR"; TypeKind["INPUT_OBJECT"] = "INPUT_OBJECT"; TypeKind["DIRECTIVE"] = "DIRECTIVE"; })(TypeKind || (TypeKind = {})); export var ArgumentKind; (function (ArgumentKind) { ArgumentKind["SCALAR"] = "SCALAR"; ArgumentKind["OBJECT"] = "OBJECT"; ArgumentKind["ENUM"] = "ENUM"; })(ArgumentKind || (ArgumentKind = {})); const MISSING = 'MISSING'; export function createSubgraphStateBuilder(graph, typeDefs, version, links) { const federationLink = links.find(isFederationLink); const linksWithDirective = links.filter(link => !isFederationLink(link) && link.imports.some(im => im.kind === 'directive')); const isLinkSpecManuallyProvided = typeDefs.definitions.some(def => def.kind === Kind.DIRECTIVE_DEFINITION && def.name.value === 'link' && def.locations.every(loc => loc.value === 'SCHEMA')); const specifiedScalars = specifiedScalarTypes.map(type => type.name); const specifiedDirectives = specifiedDirectiveTypes.map(directive => directive.name); const state = { graph: { ...graph, version, }, types: new Map(), schema: {}, links: linksWithDirective, specs: { tag: false, cost: { used: false, names: { cost: null, listSize: null, }, }, inaccessible: false, authenticated: false, requiresScopes: false, policy: false, link: isLinkSpecManuallyProvided, }, federation: { version, imports: federationLink?.imports ?? [], }, }; const schemaDef = typeDefs.definitions.find(isSchemaDefinition); const leafTypeNames = new Set(specifiedScalars); const enumTypeNames = new Set(); const inputObjectTypeNames = new Set(); for (const typeDef of typeDefs.definitions) { if (typeDef.kind === Kind.ENUM_TYPE_DEFINITION || typeDef.kind === Kind.ENUM_TYPE_EXTENSION) { enumTypeNames.add(typeDef.name.value); leafTypeNames.add(typeDef.name.value); } else if (typeDef.kind === Kind.SCALAR_TYPE_DEFINITION || typeDef.kind === Kind.SCALAR_TYPE_EXTENSION) { leafTypeNames.add(typeDef.name.value); } else if (typeDef.kind === Kind.INPUT_OBJECT_TYPE_DEFINITION || typeDef.kind === Kind.INPUT_OBJECT_TYPE_EXTENSION) { inputObjectTypeNames.add(typeDef.name.value); } } const expectedQueryTypeName = decideOnRootTypeName(schemaDef, OperationTypeNode.QUERY, 'Query'); const expectedMutationTypeName = decideOnRootTypeName(schemaDef, OperationTypeNode.MUTATION, 'Mutation'); const expectedSubscriptionTypeName = decideOnRootTypeName(schemaDef, OperationTypeNode.SUBSCRIPTION, 'Subscription'); const composedDirectives = new Set(); const directiveBuilder = directiveFactory(state); const scalarTypeBuilder = scalarTypeFactory(state); const interfaceTypeBuilder = interfaceTypeFactory(state); const objectTypeBuilder = objectTypeFactory(state, renameObjectType, interfaceTypeBuilder, isInterfaceObject); const inputObjectTypeBuilder = inputObjectTypeFactory(state); const unionTypeBuilder = unionTypeFactory(state); const enumTypeBuilder = enumTypeFactory(state); function resolveArgumentKind(typeName) { if (enumTypeNames.has(typeName)) { return ArgumentKind.ENUM; } if (inputObjectTypeNames.has(typeName)) { return ArgumentKind.OBJECT; } return ArgumentKind.SCALAR; } function renameObjectType(typeName) { if (typeName === expectedQueryTypeName) { return 'Query'; } if (typeName === expectedMutationTypeName) { return 'Mutation'; } if (typeName === expectedSubscriptionTypeName) { return 'Subscription'; } return typeName; } function isInterfaceObject(typeName) { const found = state.types.get(typeName); if (!found) { return false; } if (found.kind !== TypeKind.INTERFACE) { return false; } return found.isInterfaceObject; } return { isInterfaceObject, directive: directiveBuilder, scalarType: scalarTypeBuilder, objectType: objectTypeBuilder, interfaceType: interfaceTypeBuilder, inputObjectType: inputObjectTypeBuilder, unionType: unionTypeBuilder, enumType: enumTypeBuilder, composedDirectives, state, markCostSpecAsUsed(directive, name) { state.specs.cost.used = true; state.specs.cost.names[directive] = name; }, markSpecAsUsed(specName) { state.specs[specName] = true; }, visitor(typeNodeInfo) { const enumTypes = typeDefs.definitions.filter(isEnumType); const enumTypesByName = new Set(enumTypes ? enumTypes.map(enumType => enumType.name.value) : []); return { FieldDefinition(node) { const typeDef = typeNodeInfo.getTypeDef(); if (!typeDef) { throw new Error(`Expected to find a type definition or extension`); } const isInterfaceType = typeDef.kind === Kind.INTERFACE_TYPE_DEFINITION || typeDef.kind === Kind.INTERFACE_TYPE_EXTENSION; const isObjectType = typeDef.kind === Kind.OBJECT_TYPE_DEFINITION || typeDef.kind === Kind.OBJECT_TYPE_EXTENSION; const outputTypeName = resolveTypeName(node.type); const isLeaf = leafTypeNames.has(outputTypeName); const referencesEnumType = enumTypesByName.has(outputTypeName); if (referencesEnumType) { enumTypeBuilder.setReferencedByOutputType(outputTypeName, `${typeDef.name.value}.${node.name.value}`); } if (isInterfaceType || isInterfaceObject(typeDef.name.value)) { interfaceTypeBuilder.field.setType(typeDef.name.value, node.name.value, printOutputType(node.type)); interfaceTypeBuilder.field.setUsed(typeDef.name.value, node.name.value); if (isLeaf) { interfaceTypeBuilder.field.setLeaf(typeDef.name.value, node.name.value); } return; } if (!isObjectType) { throw new Error(`Expected to find an object type`); } objectTypeBuilder.field.setType(typeDef.name.value, node.name.value, printOutputType(node.type)); if (isLeaf) { objectTypeBuilder.field.setLeaf(typeDef.name.value, node.name.value); } if (typeDef.kind === Kind.OBJECT_TYPE_EXTENSION) { objectTypeBuilder.field.setExtension(typeDef.name.value, node.name.value); } if (version === 'v1.0' && (typeDef.kind === Kind.OBJECT_TYPE_DEFINITION || typeDef.name.value === expectedQueryTypeName || typeDef.name.value === expectedMutationTypeName || typeDef.name.value === expectedSubscriptionTypeName)) { objectTypeBuilder.field.setShareable(typeDef.name.value, node.name.value); } }, InputValueDefinition(node) { const typeDef = typeNodeInfo.getTypeDef(); const fieldDef = typeNodeInfo.getFieldDef(); if (!typeDef) { return; } const isInputObjectType = typeDef.kind === Kind.INPUT_OBJECT_TYPE_DEFINITION || typeDef.kind === Kind.INPUT_OBJECT_TYPE_EXTENSION; const isObjectType = typeDef.kind === Kind.OBJECT_TYPE_DEFINITION || typeDef.kind === Kind.OBJECT_TYPE_EXTENSION; const isInterfaceType = typeDef.kind === Kind.INTERFACE_TYPE_DEFINITION || typeDef.kind === Kind.INTERFACE_TYPE_EXTENSION; const outputTypeName = resolveTypeName(node.type); const referencesEnumType = enumTypesByName.has(outputTypeName); if (isInputObjectType) { inputObjectTypeBuilder.field.setType(typeDef.name.value, node.name.value, printOutputType(node.type)); inputObjectTypeBuilder.field.setKind(typeDef.name.value, node.name.value, resolveArgumentKind(outputTypeName)); if (referencesEnumType) { enumTypeBuilder.setReferencedByInputType(outputTypeName, `${typeDef.name.value}.${node.name.value}`); } if (node.defaultValue) { inputObjectTypeBuilder.field.setDefaultValue(typeDef.name.value, node.name.value, print(node.defaultValue)); } } if (isObjectType && fieldDef) { objectTypeBuilder.field.arg.setType(typeDef.name.value, fieldDef.name.value, node.name.value, printOutputType(node.type)); objectTypeBuilder.field.arg.setKind(typeDef.name.value, fieldDef.name.value, node.name.value, resolveArgumentKind(outputTypeName)); if (node.defaultValue) { objectTypeBuilder.field.arg.setDefaultValue(typeDef.name.value, fieldDef.name.value, node.name.value, print(node.defaultValue)); } if (referencesEnumType) { enumTypeBuilder.setReferencedByInputType(outputTypeName, `${typeDef.name.value}.${fieldDef.name.value}(${node.name.value}:)`); } } if (isInterfaceType && fieldDef) { interfaceTypeBuilder.field.arg.setType(typeDef.name.value, fieldDef.name.value, node.name.value, printOutputType(node.type)); interfaceTypeBuilder.field.arg.setKind(typeDef.name.value, fieldDef.name.value, node.name.value, resolveArgumentKind(outputTypeName)); if (node.defaultValue) { interfaceTypeBuilder.field.arg.setDefaultValue(typeDef.name.value, fieldDef.name.value, node.name.value, print(node.defaultValue)); } } }, ObjectTypeDefinition(node) { if (hasInterfaceObjectDirective(node)) { interfaceTypeBuilder.setDefinition(node.name.value); interfaceTypeBuilder.setInterfaceObject(node.name.value); if (node.interfaces) { for (const interfaceNode of node.interfaces) { interfaceTypeBuilder.setInterface(node.name.value, interfaceNode.name.value); } } return; } objectTypeBuilder.setDefinition(node.name.value); if (node.name.value === expectedQueryTypeName) { state.schema.queryType = renameObjectType(node.name.value); } else if (node.name.value === expectedMutationTypeName) { state.schema.mutationType = renameObjectType(node.name.value); } else if (node.name.value === expectedSubscriptionTypeName) { state.schema.subscriptionType = renameObjectType(node.name.value); } if (node.interfaces) { for (const interfaceNode of node.interfaces) { objectTypeBuilder.setInterface(node.name.value, interfaceNode.name.value); } } }, ObjectTypeExtension(node) { if (hasInterfaceObjectDirective(node)) { } if (node.name.value === expectedQueryTypeName) { state.schema.queryType = renameObjectType(node.name.value); } else if (node.name.value === expectedMutationTypeName) { state.schema.mutationType = renameObjectType(node.name.value); } else if (node.name.value === expectedSubscriptionTypeName) { state.schema.subscriptionType = renameObjectType(node.name.value); } objectTypeBuilder.setExtension(node.name.value, 'extend'); if (node.interfaces) { for (const interfaceNode of node.interfaces) { objectTypeBuilder.setInterface(node.name.value, interfaceNode.name.value); } } }, InterfaceTypeDefinition(node) { interfaceTypeBuilder.setDefinition(node.name.value); if (node.interfaces) { for (const interfaceNode of node.interfaces) { interfaceTypeBuilder.setInterface(node.name.value, interfaceNode.name.value); } } }, InterfaceTypeExtension(node) { if (version !== 'v1.0') { interfaceTypeBuilder.setExtension(node.name.value); } if (node.interfaces) { for (const interfaceNode of node.interfaces) { interfaceTypeBuilder.setInterface(node.name.value, interfaceNode.name.value); } } }, UnionTypeDefinition(node) { unionTypeBuilder.setDefinition(node.name.value); if (node.types) { for (const member of node.types) { unionTypeBuilder.setMember(node.name.value, member.name.value); } } }, UnionTypeExtension(node) { if (node.types) { for (const member of node.types) { unionTypeBuilder.setMember(node.name.value, member.name.value); } } }, EnumTypeDefinition(node) { enumTypeBuilder.setDefinition(node.name.value); }, EnumValueDefinition(node) { const typeDef = typeNodeInfo.getTypeDef(); if (!typeDef) { return; } enumTypeBuilder.value.setValue(typeDef.name.value, node.name.value); }, InputObjectTypeDefinition(node) { inputObjectTypeBuilder.setDefinition(node.name.value); }, ScalarTypeDefinition(node) { if (!specifiedScalars.includes(node.name.value)) { scalarTypeBuilder.setDefinition(node.name.value); } }, ScalarTypeExtension() { }, Directive(node) { if (composedDirectives.has(node.name.value)) { const typeDef = typeNodeInfo.getTypeDef(); const fieldDef = typeNodeInfo.getFieldDef(); const enumValueDef = typeNodeInfo.getValueDef(); const argDef = typeNodeInfo.getArgumentDef(); if (!typeDef) { return; } switch (typeDef.kind) { case Kind.OBJECT_TYPE_DEFINITION: case Kind.OBJECT_TYPE_EXTENSION: if (argDef) { objectTypeBuilder.field.arg.setDirective(typeDef.name.value, fieldDef.name.value, argDef.name.value, node); } else if (fieldDef) { objectTypeBuilder.field.setDirective(typeDef.name.value, fieldDef.name.value, node); } else { objectTypeBuilder.setDirective(typeDef.name.value, node); } break; case Kind.INTERFACE_TYPE_DEFINITION: case Kind.INTERFACE_TYPE_EXTENSION: if (argDef) { interfaceTypeBuilder.field.arg.setDirective(typeDef.name.value, fieldDef.name.value, argDef.name.value, node); } else if (fieldDef) { interfaceTypeBuilder.field.setDirective(typeDef.name.value, fieldDef.name.value, node); } else { interfaceTypeBuilder.setDirective(typeDef.name.value, node); } break; case Kind.SCALAR_TYPE_DEFINITION: case Kind.SCALAR_TYPE_EXTENSION: { scalarTypeBuilder.setDirective(typeDef.name.value, node); break; } case Kind.DIRECTIVE_DEFINITION: { if (fieldDef) { directiveBuilder.arg.setDirective(typeDef.name.value, fieldDef.name.value, node); } break; } case Kind.INPUT_OBJECT_TYPE_DEFINITION: case Kind.INPUT_OBJECT_TYPE_EXTENSION: { if (fieldDef) { inputObjectTypeBuilder.field.setDirective(typeDef.name.value, fieldDef.name.value, node); } else { inputObjectTypeBuilder.setDirective(typeDef.name.value, node); } break; } case Kind.ENUM_TYPE_DEFINITION: case Kind.ENUM_TYPE_EXTENSION: { if (enumValueDef) { enumTypeBuilder.value.setDirective(typeDef.name.value, enumValueDef.name.value, node); } else { enumTypeBuilder.setDirective(typeDef.name.value, node); } break; } case Kind.UNION_TYPE_DEFINITION: case Kind.UNION_TYPE_EXTENSION: { unionTypeBuilder.setDirective(typeDef.name.value, node); break; } default: throw new Error(`Directives on "${typeof typeDef === 'object' && typeDef !== null && 'kind' in typeDef ? typeDef.kind : typeDef}" types are not supported yet`); } } else if (node.name.value === 'specifiedBy') { const typeDef = typeNodeInfo.getTypeDef(); if (typeDef && (typeDef.kind === Kind.SCALAR_TYPE_DEFINITION || typeDef.kind === Kind.SCALAR_TYPE_EXTENSION)) { const urlValue = node.arguments?.find(arg => arg.name.value === 'url')?.value; if (urlValue?.kind === Kind.STRING) { scalarTypeBuilder.setSpecifiedBy(typeDef.name.value, urlValue.value); } } } else if (node.name.value === 'deprecated') { const typeDef = typeNodeInfo.getTypeDef(); const fieldDef = typeNodeInfo.getFieldDef(); const argDef = typeNodeInfo.getArgumentDef(); if (!typeDef) { return; } const reasonValue = node.arguments?.find(arg => arg.name.value === 'reason')?.value; const reason = reasonValue?.kind === Kind.STRING ? reasonValue.value : undefined; switch (typeDef.kind) { case Kind.OBJECT_TYPE_DEFINITION: case Kind.OBJECT_TYPE_EXTENSION: { if (!fieldDef) { return; } if (argDef) { objectTypeBuilder.field.arg.setDeprecated(typeDef.name.value, fieldDef.name.value, argDef.name.value, reason); } else { objectTypeBuilder.field.setDeprecated(typeDef.name.value, fieldDef.name.value, reason); } break; } case Kind.INTERFACE_TYPE_DEFINITION: case Kind.INTERFACE_TYPE_EXTENSION: { if (!fieldDef) { return; } if (argDef) { interfaceTypeBuilder.field.arg.setDeprecated(typeDef.name.value, fieldDef.name.value, argDef.name.value, reason); } else { interfaceTypeBuilder.field.setDeprecated(typeDef.name.value, fieldDef.name.value, reason); } break; } case Kind.ENUM_TYPE_DEFINITION: case Kind.ENUM_TYPE_EXTENSION: { const valueDef = typeNodeInfo.getValueDef(); if (!valueDef) { return; } enumTypeBuilder.value.setDeprecated(typeDef.name.value, valueDef.name.value, reason); break; } case Kind.INPUT_OBJECT_TYPE_DEFINITION: case Kind.INPUT_OBJECT_TYPE_EXTENSION: { if (!fieldDef) { return; } inputObjectTypeBuilder.field.setDeprecated(typeDef.name.value, fieldDef.name.value, reason); break; } } } }, DirectiveDefinition(node) { const directiveName = node.name.value; if (node.repeatable) { directiveBuilder.setRepeatable(directiveName); } if (node.locations) { for (const location of node.locations) { directiveBuilder.setLocation(directiveName, location.value); } } if (node.arguments?.length) { for (const arg of node.arguments) { directiveBuilder.arg.setType(directiveName, arg.name.value, printOutputType(arg.type)); const outputTypeName = resolveTypeName(arg.type); directiveBuilder.arg.setKind(directiveName, arg.name.value, resolveArgumentKind(outputTypeName)); if (typeof arg.defaultValue !== 'undefined') { directiveBuilder.arg.setDefaultValue(directiveName, arg.name.value, print(arg.defaultValue)); } } } }, StringValue(node, _, parent) { const typeDef = typeNodeInfo.getTypeDef(); const fieldDef = typeNodeInfo.getFieldDef(); const argDef = typeNodeInfo.getArgumentDef(); const description = { value: node.value, block: node.block === true, }; if (parent && 'kind' in parent) { if (parent.kind === Kind.SCALAR_TYPE_DEFINITION || parent.kind === Kind.SCALAR_TYPE_EXTENSION) { scalarTypeBuilder.setDescription(parent.name.value, description); } if (parent.kind === Kind.INPUT_VALUE_DEFINITION && parent.defaultValue?.kind === Kind.STRING && parent.defaultValue === node) { return; } } if (!typeDef) { return; } function matchesParent(node) { return node === parent; } switch (typeDef.kind) { case Kind.OBJECT_TYPE_DEFINITION: case Kind.OBJECT_TYPE_EXTENSION: { if (argDef && matchesParent(argDef)) { objectTypeBuilder.field.arg.setDescription(typeDef.name.value, fieldDef.name.value, argDef.name.value, description); } else if (fieldDef && matchesParent(fieldDef)) { objectTypeBuilder.field.setDescription(typeDef.name.value, fieldDef.name.value, description); } else if (matchesParent(typeDef)) { objectTypeBuilder.setDescription(typeDef.name.value, description); } break; } case Kind.INTERFACE_TYPE_DEFINITION: case Kind.INTERFACE_TYPE_EXTENSION: { if (argDef && matchesParent(argDef)) { interfaceTypeBuilder.field.arg.setDescription(typeDef.name.value, fieldDef.name.value, argDef.name.value, description); } else if (fieldDef && matchesParent(fieldDef)) { interfaceTypeBuilder.field.setDescription(typeDef.name.value, fieldDef.name.value, description); } else if (matchesParent(typeDef)) { interfaceTypeBuilder.setDescription(typeDef.name.value, description); } break; } case Kind.INPUT_OBJECT_TYPE_DEFINITION: case Kind.INPUT_OBJECT_TYPE_EXTENSION: { if (fieldDef && matchesParent(fieldDef)) { inputObjectTypeBuilder.field.setDescription(typeDef.name.value, fieldDef.name.value, description); } else if (matchesParent(typeDef)) { inputObjectTypeBuilder.setDescription(typeDef.name.value, description); } break; } case Kind.ENUM_TYPE_DEFINITION: case Kind.ENUM_TYPE_EXTENSION: { if (parent && 'kind' in parent && parent.kind === Kind.ENUM_VALUE_DEFINITION) { enumTypeBuilder.value.setDescription(typeDef.name.value, parent.name.value, description); } else if (matchesParent(typeDef)) { enumTypeBuilder.setDescription(typeDef.name.value, description); } break; } case Kind.UNION_TYPE_DEFINITION: case Kind.UNION_TYPE_EXTENSION: { if (matchesParent(typeDef)) { unionTypeBuilder.setDescription(typeDef.name.value, description); } break; } } }, }; }, }; } function directiveFactory(state) { return { setComposed(directiveName) { getOrCreateDirective(state, directiveName).composed = true; }, setLocation(directiveName, location) { getOrCreateDirective(state, directiveName).locations.add(location); }, setRepeatable(directiveName) { getOrCreateDirective(state, directiveName).repeatable = true; }, arg: { setTag(directiveName, argName, tag) { getOrCreateDirectiveArg(state, directiveName, argName).tags.add(tag); }, setType(directiveName, argName, argType) { getOrCreateDirectiveArg(state, directiveName, argName).type = argType; }, setKind(directiveName, argName, argKind) { getOrCreateDirectiveArg(state, directiveName, argName).kind = argKind; }, setDirective(typeName, argName, directive) { getOrCreateDirectiveArg(state, typeName, argName).ast.directives.push(directive); }, setDefaultValue(typeName, argName, defaultValue) { getOrCreateDirectiveArg(state, typeName, argName).defaultValue = defaultValue; }, setInaccessible(typeName, argName) { getOrCreateDirectiveArg(state, typeName, argName).inaccessible = true; }, }, }; } export function cleanSubgraphStateFromFederationSpec(state) { state.types.delete('_FieldSet'); state.types.delete('federation__FieldSet'); state.types.delete('federation__Policy'); state.types.delete('federation__Scope'); return state; } export function cleanSubgraphStateFromLinkSpec(state) { state.types.delete('link__Import'); state.types.delete('link__Purpose'); state.types.delete('link__Import'); state.types.delete('link'); return state; } function scalarTypeFactory(state) { return { setDefinition(typeName) { getOrCreateScalarType(state, typeName); }, setInaccessible(typeName) { getOrCreateScalarType(state, typeName).inaccessible = true; }, setAuthenticated(typeName) { getOrCreateScalarType(state, typeName).authenticated = true; }, setPolicies(typeName, policies) { getOrCreateScalarType(state, typeName).policies.push(...policies); }, setScopes(typeName, scopes) { getOrCreateScalarType(state, typeName).scopes.push(...scopes); }, setCost(typeName, cost) { getOrCreateScalarType(state, typeName).cost = cost; }, setTag(typeName, tag) { getOrCreateScalarType(state, typeName).tags.add(tag); }, setDirective(typeName, directive) { getOrCreateScalarType(state, typeName).ast.directives.push(directive); }, setDescription(typeName, description) { getOrCreateScalarType(state, typeName).description = description; }, setSpecifiedBy(typeName, url) { getOrCreateScalarType(state, typeName).specifiedBy = url; }, }; } function objectTypeFactory(state, renameObject, interfaceTypeBuilder, isInterfaceObject) { return { setDefinition(typeName) { if (isInterfaceObject(typeName)) { return interfaceTypeBuilder.setDefinition(typeName); } getOrCreateObjectType(state, renameObject, typeName).isDefinition = true; }, setExtension(typeName, extensionType) { if (isInterfaceObject(typeName)) { return interfaceTypeBuilder.setExtension(typeName); } const objectType = getOrCreateObjectType(state, renameObject, typeName); objectType.extension = true; if (objectType.extensionType !== '@extends') { objectType.extensionType = extensionType; } }, setDescription(typeName, description) { if (isInterfaceObject(typeName)) { return interfaceTypeBuilder.setDescription(typeName, description); } getOrCreateObjectType(state, renameObject, typeName).description = description; }, setExternal(typeName) { if (isInterfaceObject(typeName)) { return; } const objectType = getOrCreateObjectType(state, renameObject, typeName); objectType.external = true; for (const field of objectType.fields.values()) { field.external = true; } }, setInterface(typeName, interfaceName) { if (isInterfaceObject(typeName)) { return interfaceTypeBuilder.setInterface(typeName, interfaceName); } getOrCreateObjectType(state, renameObject, typeName).interfaces.add(interfaceName); getOrCreateInterfaceType(state, interfaceName).implementedBy.add(typeName); }, setKey(typeName, fields, fieldsUsedInKey, resolvable) { if (isInterfaceObject(typeName)) { return interfaceTypeBuilder.setKey(typeName, fields, fieldsUsedInKey, resolvable); } const objectType = getOrCreateObjectType(state, renameObject, typeName); objectType.keys.push({ fields, resolvable }); for (const field of fieldsUsedInKey) { objectType.fieldsUsedAsKeys.add(field); } }, setInaccessible(typeName) { if (isInterfaceObject(typeName)) { return interfaceTypeBuilder.setInaccessible(typeName); } const objectType = getOrCreateObjectType(state, renameObject, typeName); objectType.inaccessible = true; }, setAuthenticated(typeName) { if (isInterfaceObject(typeName)) { return interfaceTypeBuilder.setAuthenticated(typeName); } const objectType = getOrCreateObjectType(state, renameObject, typeName); objectType.authenticated = true; }, setPolicies(typeName, policies) { if (isInterfaceObject(typeName)) { return interfaceTypeBuilder.setPolicies(typeName, policies); } getOrCreateObjectType(state, renameObject, typeName).policies.push(...policies); }, setScopes(typeName, scopes) { if (isInterfaceObject(typeName)) { return interfaceTypeBuilder.setScopes(typeName, scopes); } getOrCreateObjectType(state, renameObject, typeName).scopes.push(...scopes); }, setCost(typeName, cost) { if (isInterfaceObject(typeName)) { return; } getOrCreateObjectType(state, renameObject, typeName).cost = cost; }, setShareable(typeName) { if (isInterfaceObject(typeName)) { return; } getOrCreateObjectType(state, renameObject, typeName).shareable = true; }, setTag(typeName, tag) { if (isInterfaceObject(typeName)) { return interfaceTypeBuilder.setTag(typeName, tag); } getOrCreateObjectType(state, renameObject, typeName).tags.add(tag); }, setDirective(typeName, directive) { if (isInterfaceObject(typeName)) { return interfaceTypeBuilder.setDirective(typeName, directive); } getOrCreateObjectType(state, renameObject, typeName).ast.directives.push(directive); }, field: { setType(typeName, fieldName, fieldType) { if (isInterfaceObject(typeName)) { return interfaceTypeBuilder.field.setType(typeName, fieldName, fieldType); } getOrCreateObjectField(state, renameObject, typeName, fieldName).type = fieldType; }, setLeaf(typeName, fieldName) { if (isInterfaceObject(typeName)) { return interfaceTypeBuilder.field.setLeaf(typeName, fieldName); } getOrCreateObjectField(state, renameObject, typeName, fieldName).isLeaf = true; }, setExtension(typeName, fieldName) { if (isInterfaceObject(typeName)) { return; } getOrCreateObjectField(state, renameObject, typeName, fieldName).extension = true; }, setDirective(typeName, fieldName, directive) { if (isInterfaceObject(typeName)) { return interfaceTypeBuilder.field.setDirective(typeName, fieldName, directive); } getOrCreateObjectField(state, renameObject, typeName, fieldName).ast.directives.push(directive); }, setDescription(typeName, fieldName, description) { if (isInterfaceObject(typeName)) { return interfaceTypeBuilder.field.setDescription(typeName, fieldName, description); } getOrCreateObjectField(state, renameObject, typeName, fieldName).description = description; }, setDeprecated(typeName, fieldName, reason) { if (isInterfaceObject(typeName)) { return interfaceTypeBuilder.field.setDeprecated(typeName, fieldName, reason); } getOrCreateObjectField(state, renameObject, typeName, fieldName).deprecated = { reason, deprecated: true, }; }, setAuthenticated(typeName, fieldName) { if (isInterfaceObject(typeName)) { return interfaceTypeBuilder.field.setAuthenticated(typeName, fieldName); } getOrCreateObjectField(state, renameObject, typeName, fieldName).authenticated = true; }, setPolicies(typeName, fieldName, policies) { if (isInterfaceObject(typeName)) { return interfaceTypeBuilder.field.setPolicies(typeName, fieldName, policies); } getOrCreateObjectField(state, renameObject, typeName, fieldName).policies.push(...policies); }, setScopes(typeName, fieldName, scopes) { if (isInterfaceObject(typeName)) { return interfaceTypeBuilder.field.setScopes(typeName, fieldName, scopes); } getOrCreateObjectField(state, renameObject, typeName, fieldName).scopes.push(...scopes); }, setCost(typeName, fieldName, cost) { if (isInterfaceObject(typeName)) { return interfaceTypeBuilder.field.setCost(typeName, fieldName, cost); } getOrCreateObjectField(state, renameObject, typeName, fieldName).cost = cost; }, setListSize(typeName, fieldName, listSize) { if (isInterfaceObject(typeName)) { return interfaceTypeBuilder.field.setListSize(typeName, fieldName, listSize); } getOrCreateObjectField(state, renameObject, typeName, fieldName).listSize = listSize; }, setExternal(typeName, fieldName) { if (isInterfaceObject(typeName)) { return interfaceTypeBuilder.field.setExternal(typeName, fieldName); } getOrCreateObjectField(state, renameObject, typeName, fieldName).external = true; }, setInaccessible(typeName, fieldName) { if (isInterfaceObject(typeName)) { return interfaceTypeBuilder.field.setInaccessible(typeName, fieldName); } getOrCreateObjectField(state, renameObject, typeName, fieldName).inaccessible = true; }, setOverride(typeName, fieldName, override) { if (isInterfaceObject(typeName)) { return interfaceTypeBuilder.field.setOverride(typeName, fieldName, override); } getOrCreateObjectField(state, renameObject, typeName, fieldName).override = override; }, setProvides(typeName, fieldName, provides) { if (isInterfaceObject(typeName)) { return; } getOrCreateObjectField(state, renameObject, typeName, fieldName).provides = provides; }, setRequires(typeName, fieldName, requires) { if (isInterfaceObject(typeName)) { return interfaceTypeBuilder.field.setRequires(typeName, fieldName, requires); } getOrCreateObjectField(state, renameObject, typeName, fieldName).requires = requires; }, markAsProvided(typeName, fieldName) { if (isInterfaceObject(typeName)) { return; } getOrCreateObjectField(state, renameObject, typeName, fieldName).provided = true; }, markedAsRequired(typeName, fieldName) { if (isInterfaceObject(typeName)) { return; } getOrCreateObjectField(state, renameObject, typeName, fieldName).required = true; }, setShareable(typeName, fieldName) { if (isInterfaceObject(typeName)) { return interfaceTypeBuilder.field.setShareable(typeName, fieldName); } getOrCreateObjectField(state, renameObject, typeName, fieldName).shareable = true; }, setTag(typeName, fieldName, tag) { if (isInterfaceObject(typeName)) { return interfaceTypeBuilder.field.setTag(typeName, fieldName, tag); } getOrCreateObjectField(state, renameObject, typeName, fieldName).tags.add(tag); }, setUsed(typeName, fieldName) { if (isInterfaceObject(typeName)) { return interfaceTypeBuilder.field.setUsed(typeName, fieldName); } getOrCreateObjectField(state, renameObject, typeName, fieldName).used = true; }, arg: { setType(typeName, fieldName, argName, argType) { if (isInterfaceObject(typeName)) { return interfaceTypeBuilder.field.arg.setType(typeName, fieldName, argName, argType); } getOrCreateObjectFieldArgument(state, renameObject, typeName, fieldName, argName).type = argType; }, setKind(typeName, fieldName, argName, argKind) { if (isInterfaceObject(typeName)) { return interfaceTypeBuilder.field.arg.setKind(typeName, fieldName, argName, argKind); } getOrCreateObjectFieldArgument(state, renameObject, typeName, fieldName, argName).kind = argKind; }, setDescription(typeName, fieldName, argName, description) { if (isInterfaceObject(typeName)) { return interfaceTypeBuilder.field.arg.setDescription(typeName, fieldName, argName, description); } getOrCreateObjectFieldArgument(state, renameObject, typeName, fieldName, argName).description = description; }, setDeprecated(typeName, fieldName, argName, reason) { if (isInterfaceObject(typeName)) { return interfaceTypeBuilder.field.arg.setDeprecated(typeName, fieldName, argName, reason); } getOrCreateObjectFieldArgument(state, renameObject, typeName, fieldName, argName).deprecated = { reason, deprecated: true, }; }, setDirective(typeName, fieldName, argName, directive) { if (isInterfaceObject(typeName)) { return interfaceTypeBuilder.field.arg.setDirective(typeName, fieldName, argName, directive); } getOrCreateObjectFieldArgument(state, renameObject, typeName, fieldName, argName).ast.directives.push(directive); }, setDefaultValue(typeName, fieldName, argName, defaultValue) { if (isInterfaceObject(typeName)) { return interfaceTypeBuilder.field.arg.setDefaultValue(typeName, fieldName, argName, defaultValue); } getOrCreateObjectFieldArgument(state, renameObject, typeName, fieldName, argName).defaultValue = defaultValue; }, setInaccessible(typeName, fieldName, argName) { if (isInterfaceObject(typeName)) { return interfaceTypeBuilder.field.arg.setInaccessible(typeName, fieldName, argName); } getOrCreateObjectFieldArgument(state, renameObject, typeName, fieldName, argName).inaccessible = true; }, setTag(typeName, fieldName, argName, tag) { if (isInterfaceObject(typeName)) { return interfaceTypeBuilder.field.arg.setTag(typeName, fieldName, argName, tag); } getOrCreateObjectFieldArgument(state, renameObject, typeName, fieldName, argName).tags.add(tag); }, setCost(typeName, fieldName, argName, cost) { if (isInterfaceObject(typeName)) { return interfaceTypeBuilder.field.arg.setCost(typeName, fieldName, argName, cost); } getOrCreateObjectFieldArgument(state, renameObject, typeName, fieldName, argName).cost = cost; }, }, }, }; } function interfaceTypeFactory(state) { return { setDefinition(typeName) { getOrCreateInterfaceType(state, typeName).isDefinition = true; }, setExtension(typeName) { getOrCreateInterfaceType(state, typeName).extension = true; }, setInterface(typeName, interfaceName) { getOrCreateInterfaceType(state, typeName).interfaces.add(interfaceName); }, setInterfaceObject(typeName) { getOrCreateInterfaceType(state, typeName).isInterfaceObject = true; }, setKey(typeName, fields, fieldsUsedInKey, resolvable) { const interfaceType = getOrCreateInterfaceType(state, typeName); interfaceType.keys.push({ fields, resolvable }); for (const field of fieldsUsedInKey) { interfaceType.fieldsUsedAsKeys.add(field); } }, setInaccessible(typeName) { const objectType = getOrCreateInterfaceType(state, typeName); objectType.inaccessible = true; }, setAuthenticated(typeName) { const t = getOrCreateInterfaceType(state, typeName); t.authenticated = true; },