@theguild/federation-composition
Version:
Open Source Composition library for Apollo Federation
1,650 lines • 74.2 kB
JavaScript
import { Kind, OperationTypeNode, specifiedScalarTypes, DirectiveLocation, } from "graphql";
import { print } from "../graphql/printer.js";
import { isFederationLink, } from "../specifications/federation.js";
import { printOutputType } from "./helpers.js";
import { mergeScopePolicies } from "../utils/auth.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 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;
}
}
}
else if (node.name.value === "oneOf") {
const typeDef = typeNodeInfo.getTypeDef();
if (typeDef &&
(typeDef.kind === Kind.INPUT_OBJECT_TYPE_DEFINITION ||
typeDef.kind === Kind.INPUT_OBJECT_TYPE_EXTENSION)) {
inputObjectTypeBuilder.setOneOf(typeDef.name.value);
}
}
},
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) {
const existing = getOrCreateScalarType(state, typeName);
existing.policies = mergeScopePolicies(existing.policies, policies);
},
setScopes(typeName, scopes) {
const existing = getOrCreateScalarType(state, typeName);
existing.scopes = mergeScopePolicies(existing.scopes, 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) {
const objectType = getOrCreateObjectType(state, renameObject, typeName);
objectType.authenticated = true;
},
setPolicies(typeName, policies) {
const existing = getOrCreateObjectType(state, renameObject, typeName);
existing.policies = mergeScopePolicies(existing.policies, policies);
},
setScopes(typeName, scopes) {
const existing = getOrCreateObjectType(state, renameObject, typeName);
existing.scopes = mergeScopePolicies(existing.scopes, 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);
}
let existing = getOrCreateObjectField(state, renameObject, typeName, fieldName);
existing.policies = mergeScopePolicies(existing.policies, policies);
},
setScopes(typeName, fieldName, scopes) {
if (isInterfaceObject(typeName)) {
return interfaceTypeBuilder.field.setScopes(typeName, fieldName, scopes);
}
let existing = getOrCreateObjectField(state, renameObject, typeName, fieldName);
existing.scopes = mergeScopePolicies(existing.scopes, 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, label) {
if (isInterfaceObject(typeName)) {
return interfaceTypeBuilder.field.setOverride(typeName, fieldName, override, label);
}
const field = getOrCreateObjectField(state, renameObject, typeName, fieldName);
field.override = override;
field.overrideLabel = label;
},
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;
},
setTag(typeName, tag) {
getOrCreateInterfaceType(state, typeName).tags.add(tag);
},
setDirective(typeName, directive) {
getOrCreateInterfaceType(state, typeName).ast.directives.push(directive);
},
setDescription(typeName, description) {
getOrCreateInterfaceType(state, typeName).description = description;
},
field: {
setType(typeName, fieldName, fieldType) {
getOrCreateInterfaceField(state, typeName, fieldName).type = fieldType;
},
setLeaf(typeName, fieldName) {
getOrCreateInterfaceField(state, typeName, fieldName).isLeaf = true;
},
setExternal(typeName, fieldName) {
getOrCreateInterfaceField(state, typeName, fieldName).external = true;
},
setInaccessible(typeName, fieldName) {
getOrCreateInterfaceField(state, typeName, fieldName).inaccessible =
true;
},
setAuthenticated(typeName, fieldName) {
getOrCreateInterfaceField(state, typeName, fieldName).authenticated =
true;
},
setPolicies(typeName, fieldName, policies) {
const existing = getOrCreateInterfaceField(state, typeName, fieldName);
existing.policies = mergeScopePolicies(existing.policies, policies);
},
setScopes(typeName, fieldName, scopes) {
const existing = getOrCreateInterfaceField(state, typeName, fieldName);
existing.scopes = mergeScopePolicies(existing.scopes, scopes);
},
setCost(typeName, fieldName, cost) {
getOrCreateInterfaceField(state, typeName, fieldName).cost = cost;
},
setListSize(typeName, fieldName, listSize) {
getOrCreateInterfaceField(state, typeName, fieldName).listSize =
listSize;
},
setOverride(typeName, fieldName, override, label) {
const field = getOrCreateInterfaceField(state, typeName, fieldName);
field.override = override;
field.overrideLabel = label;
},
setRequires(typeName, fieldName, requires) {
getOrCreateInterfaceField(state, typeName, fieldName).requires =
requires;
},
setShareable(typeName, fieldName) {
getOrCreateInterfaceField(state, typeName, fieldName).shareable = true;
},
setTag(typeName, fieldName, tag) {
getOrCreateInterfaceField(state, typeName, fieldName).tags.add(tag);
},
setUsed(typeName, fieldName) {
getOrCreateInterfaceField(state, typeName, fieldName).used = true;
},
setDirective(typeName, fieldName, directive) {
getOrCreateInterfaceField(state, typeName, fieldName).ast.directives.push(directive);
},
setDescription(typeName, fieldName, description) {
getOrCreateInterfaceField(state, typeName, fieldName).description =
description;
},
setDeprecated(typeName, fieldName, reason) {
getOrCreateInterfaceField(state, typeName, fieldName).deprecated = {
reason,
deprecated: true,
};
},
arg: {
setType(typeName, fieldName, argName, argType) {
getOrCreateInterfaceFieldArgument(state, typeName, fieldName, argName).type = argType;
},
setKind(typeName, fieldName, argName, argKind) {
getOrCreateInterfaceFieldArgument(state, typeName, fieldName, argName).kind = argKind;
},
setDefaultValue(typeName, fieldName, argName, defaultValue) {
getOrCreateInterfaceFieldArgument(state, typeName, fieldName, argName).defaultValue = defaultValue;
},
setDeprecated(typeName, fieldName, argName, reason) {
getOrCreateInterfaceFieldArgument(state, typeName, fieldName, argName).deprecated = {
reason,
deprecated: true,
};
},
setDescription(typeName, fieldName, argName, description) {
getOrCreateInterfaceFieldArgument(state, typeName, fieldName, argName).description = description;
},
setTag(typeName, fieldName, argName, tag) {
getOrCreateInterfaceFieldArgument(state, typeName, fieldName, argName).tags.add(tag);
},
setInaccessible(typeName, fieldName, argName) {
getOrCreateInterfaceFieldArgument(state, typeName, fieldName, argName).inaccessible = true;
},
setCost(typeName, fieldName, argName, cost) {
getOrCreateInterfaceFieldArgument(state, typeName, fieldName, argName).cost = cost;
},
setDirective(typeName, fieldName, argName, directive) {
getOrCreateInterfaceFieldArgument(state, typeName, fieldName, argName).ast.directives.push(directive);
},
},
},
};
}
function inputObjectTypeFactory(state) {
return {
setDefinition(typeName) {
getOrCreateInputObjectType(state, typeName).isDefinition = true;
},
setExtension(typeName) {
getOrCreateInputObjectType(state, typeName).extension = true;
},
setDescription(typeName, description) {
getOrCreateInputObjectType(state, typeName).description = description;
},
setInaccessible(typeName) {
const inputObjectType = getOrCreateInputObjectType(state, typeName);
inputObjectType.inaccessible = true;
for (const field of inputObjectType.fields.values()) {
field.inaccessible = true;
}
},
setDirective(typeName, directive) {
getOrCreateInputObjectType(state, typeName).ast.directives.push(directive);
},
setTag(typeName, tag) {
getOrCreateInputObjectType(state, typeName).tags.add(tag);
},
setOneOf(typeName) {
const existingOneOf = state.types.get("oneOf");
if (existingOneOf &&
existingOneOf.kind === TypeKind.DIRECTIVE &&
existingOneOf.locations.size === 1 &&
existingOneOf.locations.has(DirectiveLocation.INPUT_OBJECT) &&
!existingOneOf.repeatable &&
existingOneOf.args.size === 0) {
existingOneOf.composed = true;
getOrCreateInputObjectType(state, typeName).isOneOf = true;
}
else if (!existingOneOf) {
const oneOfDirective = getOrCreateDirective(state, "oneOf");
oneOfDirective.locations.add(DirectiveLocation.INPUT_OBJECT);
oneOfDirective.composed = true;
getOrCreateInputObjectType(state, typeName).isOneOf = true;
}
},
field: {
setType(typeName, fieldName, fieldType) {
getOrCreateInputObjectField(state, typeName, fieldName).type =
fieldType;
},
setKind(typeName, fieldName, fieldKind) {
getOrCreateInputObjectField(state, typeName, fieldName).kind =
fieldKind;
},
setDescription(typeName, fieldName, description) {
getOrCreateInputObjectField(state, typeName, fieldName).description =
description;
},
setDeprecated(typeName, fieldName, reason) {
getOrCreateInputObjectField(state, typeName, fieldName).deprecated = {
reason,
deprecated: true,
};
},
setDefaultValue(typeName, fieldName, defaultValue) {
getOrCreateInputObjectField(state, typeName, fieldName).defaultValue =
defaultValue;
},
setInaccessible(typeName, fieldName) {
getOrCreateInputObjectField(state, typeName, fieldName).inaccessible =
true;
},
setTag(typeName, fieldName, tag) {
getOrCreateInputObjectField(state, typeName, fieldName).tags.add(tag);
},
setDirective(typeName, fieldName, directive) {
getOrCreateInputObjectField(state, typeName, fieldName).ast.directives.push(directive);
},
setCost(typeName, fieldName, cost) {
getOrCreateInputObjectField(state, typeName, fieldName).cost = cost;
},
},
};
}
function unionTypeFactory(state) {
return {
setDefinition(typeName) {
getOrCreateUnionType(state, typeName).isDefinition = true;
},
setInaccessible(typeName) {
getOrCreateUnionType(state, typeName).inaccessible = true;
},
setTag(typeName, tag) {
getOrCreateUnionType(state, typeName).tags.add(tag);
},
setDescription(typeName, description) {
getOrCreateUnionType(state, typeName).description = description;
},
setMember(typeName, member) {
getOrCreateUnionType(state, typeName).members.add(member);
},
setDirective(typeName, directive) {
getOrCreateUnionType(state, typeName).ast.directives.push(directive);
},
};
}
function enumTypeFactory(state) {
return {
setDefinition(typeName) {
getOrCreateEnumType(state, typeName).isDefinition = true;
},
setInaccessible(typeName) {
getOrCreateEnumType(state, typeName).inaccessible = true;
},
setAuthenticated(typeName) {
getOrCreateEnumType(state, typeName).authenticated = true;
},
setPolicies(typeName, policies) {
const existing = getOrCreateEnumType(state, typeName);
existing.policies = mergeScopePolicies(existing.policies, policies);
},
setScopes(typeName, scopes) {
const existing = getOrCreateEnumType(state, typeName);
existing.scopes = mergeScopePolicies(existing.scopes, scopes);
},
setCost(typeName, cost) {
getOrCreateEnumType(state, typeName).cost = cost;
},
setDescription(typeName, description) {
getOrCreateEnumType(state, typeName).description = description;
},
setTag(typeName, tag) {
getOrCreateEnumType(state, typeName).tags.add(tag);
},
setReferencedByInputType(typeName, schemaCoordinate) {
getOrCreateEnumType(state, typeName).referencedByInputType = true;
getOrCreateEnumType(state, typeName).inputTypeReferences.add(schemaCoordinate);
},
setReferencedByOutputType(typeName, schemaCoordinate) {
getOrCreateEnumType(state, typeName).referencedByOutputType = true;
getOrCreateEnumType(state, typeName).outputTypeReferences.add(schemaCoordinate);
},
setDirective(typeName, directive) {
getOrCreateEnumType(state, typeName).ast.directives.push(directive);
},
value: {
setValue(typeName, valueName) {
getOrCreateEnumValue(state, typeName, valueName);
},
setDescription(typeName, valueName, description) {
getOrCreateEnumValue(state, typeName, valueName).description =
description;
},
setDirective(typeName, valueName, directive) {
getOrCreateEnumValue(state, typeName, valueName).ast.directives.push(directive);
},
setInaccessible(typeName, valueName) {
getOrCreateEnumValue(state, typeName, valueName).inaccessible = true;
},
setTag(typeName, valueName, tag) {
getOrCreateEnumValue(state, typeName, valueName).tags.add(tag);
},
setDeprecated(typeName, valueName, reason) {
getOrCreateEnumValue(state, typeName, valueName).deprecated = {
reason,
deprecated: true,
};
},
},
};
}
const executableDirectiveLocations = new Set([
DirectiveLocation.FIELD,
DirectiveLocation.FRAGMENT_DEFINITION,
DirectiveLocation.INLINE_FRAGMENT,
DirectiveLocation.FRAGMENT_SPREAD,
DirectiveLocation.VARIABLE_DEFINITION,
DirectiveLocation.QUERY,
DirectiveLocation.MUTATION,
DirectiveLocation.SUBSCRIPTION,
]);
export function isExecutableDirectiveLocation(location) {
return executableDirectiveLocations.has(location);
}
function getOrCreateDirective(state, directiveName) {
const existing = state.types.get(directiveName);
if (existing) {
if (existing.kind !== TypeKind.DIRECTIVE) {
throw new Error(`Expected ${directiveName} to be a directive`);
}
return existing;
}
const directive = {
kind: TypeKind.DIRECTIVE,
name: directiveName,
locations: new Set(),
repeatable: false,
composed: false,
get isExecutable() {
return Array.from(this.locations).some((location) => isExecutableDirectiveLocation(location));
},
args: new Map(),
};
state.types.set(directiveName, directive);
return directive;
}
function getOrCreateDirectiveArg(state, directiveName, argName) {
const directive = getOrCreateDirective(state, directiveName);
const existing = directive.args.get(argName);
if (existing) {
return existing;
}
const arg = {
name: argName,
type: MISSING,
kind: ArgumentKind.SCALAR,
inaccessible: false,
tags: new Set(),
cost: null,
ast: {
directives: [],
},
};
directive.args.set(argName, arg);
return arg;
}
function getOrCreateScalarType(state, typeName) {
const existing = state.types.get(typeName);
if (existing) {
if (existing.kind !== TypeKind.SCALAR) {
throw new Error(`Expected ${typeName} to be a scalar type`);
}
return existing;
}
const scalarType = {
kind: TypeKind.SCALAR,
name: typeName,
tags: new Set(),
inaccessible: false,
authenticated: false,
policies: [],
scopes: [],
cost: null,
ast: {
directives: [],
},
};
state.types.set(typeName, scalarType);
return scalarType;
}
function getOrCreateObjectType(state, renameObject, typeName) {
typeName = renameObject(typeName);
const existing = state.types.get(typeName);
if (existing) {
if (existing.kind !== TypeKind.OBJECT) {
throw new Error(`Expected ${typeName} to be an object type`);
}
return existing;
}
const objectType = {
kind: TypeKind.OBJECT,
name: typeName,
fields: new Map(),
fieldsUsedAsKeys: new Set(),
extension: false,
external: false,
keys: [],
inaccessible: false,
authenticated: false,
policies: [],
scopes: [],
cost: null,
shareable: false,
tags: new Set(),
interfaces: new Set(),
isDefinition: false,
ast: {
directives: [],
},
};
state.types.set(typeName, objectType);
return objectType;
}
function getOrCreateInterfaceType(state, typeName) {
const existing = state.types.get(typeName);
if (existing) {
if (existing.kind !== TypeKind.INTERFACE) {
throw new Error(`Expected ${typeName} to be an interface type`);
}
return existing;
}
const interfaceType = {
kind: TypeKind.INTERFACE,
name: typeName,
fields: new Map(),
fieldsUsedAsKeys: new Set(),
extension: false,
keys: [],
inaccessible: false,
tags: new Set(),
interfaces: new Set(),
implementedBy: new Set(),
isDefinition: false,
isInterfaceObject: false,
ast: {
directives: [],
},
};
state.types.set(typeName, interfaceType);
return interfaceType;
}
function getOrCreateInputObjectType(state, typeName) {
const existing = state.types.get(typeName);
if (existing) {
if (existing.kind !== TypeKind.INPUT_OBJECT) {
throw new Error(`Expected ${typeName} to be an input object type`);
}
return existing;
}
const inputObjectType = {
kind: TypeKind.INPUT_OBJECT,
name: typeName,
fields: new Map(),
extension: false,
inaccessible: false,
tags: new Set(),
isDefinition: false,
ast: {
directives: [],
},
};
state.types.set(typeName, inputObjectType);
return inputObjectType;
}
function getOrCreateEnumType(state, typeName) {
const existing = state.types.get(typeName);
if (existing) {
if (existing.kind !== TypeKind.ENUM) {
throw new Error(`Expected ${typeName} to be an enum type`);
}
return existing;
}
const enumType = {
kind: TypeKind.ENUM,
name: typeName,
values: new Map(),
inaccessible: false,
authenticated: false,
policies: [],
scopes: [],
cost: null,
tags: new Set(),
isDefinition: false,
referencedByInputType: false,
referencedByOutputType: false,
inputTypeReferences: new Set(),
outputTypeReferences: new Set(),
ast: {
directives: [],
},
};
state.types.set(typeName, enumType);
return enumType;
}
function getOrCreateUnionType(state, typeName) {
const existing = state.types.get(typeName);
if (existing) {
if (existing.kind !== TypeKind.UNION) {
throw new Error(`Expected ${typeName} to be a union type`);
}
return existing;
}
const unionType = {
kind: TypeKind.UNION,
name: typeName,
members: new Set(),
inaccessible: false,
tags: new Set(),
isDefinition: false,
ast: {
directives: [],
},
};
state.types.set(typeName, unionType);
return unionType;
}
function getOrCreateObjectField(state, renameObject, typeName, fieldName) {
const objectType = getOrCreateObjectType(state, renameObject, typeName);
const existing = objectType.fields.get(fieldName);
if (existing) {
return existing;
}
const field = {
name: fieldName,
type: MISSING,
usedAsKey: false,
isLeaf: false,
external: false,
inaccessible: false,
authenticated: false,
extension: false,
policies: [],
scopes: [],
cost: null,
listSize: null,
used: false,
required: false,
provided: false,
override: null,
overrideLabel: null,
provides: null,
requires: null,
shareable: false,
tags: new Set(),
args: new Map(),
ast: {
directives: [],
},
};
objectType.fields.set(fieldName, field);
return field;
}
function getOrCreateInterfaceField(state, typeName, fieldName) {
const interfaceType = getOrCreateInterfaceType(state, typeName);
const existing = interfaceType.fields.get(fieldName);
if (existing) {
return existing;
}
const field = {
name: fieldName,
usedAsKey: false,
isLeaf: false,
type: MISSING,
external: false,
inaccessible: false,
authenticated: false,
policies: [],
scopes: [],
cost: null,
listSize: null,
used: false,
override: null,
overrideLabel: null,
provides: null,
requires: null,
required: false,
provided: false,
shareable: false,
extension: false,
tags: new Set(),
args: new Map(),
ast: {
directives: [],
},
};
interfaceType.fields.set(fieldName, field);
return field;
}
function getOrCreateInputObjectField(state, typeName, fieldName) {
const inputObjectType = getOrCreateInputObjectType(state, typeName);
const existing = inputObjectType.fields.get(fieldName);
if (existing) {
return existing;
}
const field = {
name: fieldName,
type: MISSING,
kind: ArgumentKind.SCALAR,
inaccessible: false,
cost: null,
tags: new Set(),
ast: {
directives: [],
},
};
inputObjectType.fields.set(fieldName, field);
return field;
}
function getOrCreateEnumValue(state, typeName, enumValueName) {
const enumType = getOrCreateEnumType(state, typeName);
const existing = enumType.values.get(enumValueName);
if (existing) {
return existing;
}
const enumValue = {
name: enumValueName,
inaccessible: false,
tags: new Set(),
ast: {
directives: [],
},
};
enumType.values.set(enumValueName, enumValue);
return enumValue;
}
function getOrCreateObjectFieldArgument(state, renameObject, typeName, fieldName, argName) {
const fieldState = getOrCreateObjectField(state, renameObject, typeName, fieldName);
const existing = fieldState.args.get(argName);
if (existing) {
return existing;
}
const arg = {
name: argName,
type: MISSING,
kind: ArgumentKind.SCALAR,
inaccessible: false,
tags: new Set(),
cost: null,
ast: {
directives: [],
},
};
fieldState.args.set(argName, arg);
return arg;
}
function getOrCreateInterfaceFieldArgument(state, typeName, fieldName, argName) {
const fieldState = getOrCreateInterfaceField(state, typeName, fieldName);
const existing = fieldState.args.get(argName);
if (existing) {
return existing;
}
const arg = {
name: argName,
type: MISSING,
kind: ArgumentKind.SCALAR,
inaccessible: false,
tags: new Set(),
cost: null,
ast: {
directives: [],
},
};
fieldState.args.set(argName, arg);
return arg;
}
function isSchemaDefinition(node) {
return node.kind === Kind.SCHEMA_DEFINITION;
}
function resolveTypeName(node) {
switch (node.kind) {
case Kind.NAMED_TYPE:
return node.name.value;
case Kind.LIST_TYPE:
return resolveTypeName(node.type);
case Kind.NON_NULL_TYPE:
return resolveTypeName(node.type);
default:
throw new Error(`Unexpected type node: ${node}`);
}
}
function isEnumType(node) {
return (node.kind === Kind.ENUM_TYPE_DEFINITION ||
node.kind === Kind.ENUM_TYPE_EXTENSION);
}
function decideOnRootTypeName(schemaDef, kind, defaultName) {
return (schemaDef?.operationTypes?.find((operationType) => operationType.operation === kind)?.type.name.value ?? defaultName);
}
function hasInterfaceObjectDirective(node) {
return node.directives?.some((d) => d.name.value === "interfaceObject");
}