@theguild/federation-composition
Version:
Open Source Composition library for Apollo Federation
975 lines (974 loc) • 72 kB
JavaScript
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;
},