UNPKG

@apollo/federation-internals

Version:
362 lines 17.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.builtTypeReference = exports.buildSchemaFromAST = exports.buildSchema = void 0; const graphql_1 = require("graphql"); const values_1 = require("./values"); const definitions_1 = require("./definitions"); const error_1 = require("./error"); const introspection_1 = require("./introspection"); function buildValue(value) { return value ? (0, values_1.valueFromASTUntyped)(value) : undefined; } function buildSchema(source, options) { return buildSchemaFromAST((0, graphql_1.parse)(source), options); } exports.buildSchema = buildSchema; function buildSchemaFromAST(documentNode, options) { var _a; const errors = []; const schema = new definitions_1.Schema(options === null || options === void 0 ? void 0 : options.blueprint); const { directiveDefinitions, typeDefinitions, typeExtensions, schemaDefinitions, schemaExtensions, } = buildNamedTypeAndDirectivesShallow(documentNode, schema, errors); for (const typeNode of typeDefinitions) { if (typeNode.kind === graphql_1.Kind.ENUM_TYPE_DEFINITION) { buildEnumTypeValuesWithoutDirectiveApplications(typeNode, schema.type(typeNode.name.value)); } } for (const typeExtensionNode of typeExtensions) { if (typeExtensionNode.kind === graphql_1.Kind.ENUM_TYPE_EXTENSION) { const toExtend = schema.type(typeExtensionNode.name.value); const extension = toExtend.newExtension(); extension.sourceAST = typeExtensionNode; buildEnumTypeValuesWithoutDirectiveApplications(typeExtensionNode, schema.type(typeExtensionNode.name.value), extension); } } for (const directiveDefinitionNode of directiveDefinitions) { buildDirectiveDefinitionInnerWithoutDirectiveApplications(directiveDefinitionNode, schema.directive(directiveDefinitionNode.name.value), errors); } for (const schemaDefinition of schemaDefinitions) { buildSchemaDefinitionInner(schemaDefinition, schema.schemaDefinition, errors); } for (const schemaExtension of schemaExtensions) { buildSchemaDefinitionInner(schemaExtension, schema.schemaDefinition, errors, schema.schemaDefinition.newExtension()); } errors.push(...schema.blueprint.onDirectiveDefinitionAndSchemaParsed(schema)); for (const directiveDefinitionNode of directiveDefinitions) { buildDirectiveApplicationsInDirectiveDefinition(directiveDefinitionNode, schema.directive(directiveDefinitionNode.name.value), errors); } for (const typeNode of typeDefinitions) { buildNamedTypeInner(typeNode, schema.type(typeNode.name.value), schema.blueprint, errors); } for (const typeExtensionNode of typeExtensions) { const toExtend = schema.type(typeExtensionNode.name.value); const extension = toExtend.newExtension(); extension.sourceAST = typeExtensionNode; buildNamedTypeInner(typeExtensionNode, toExtend, schema.blueprint, errors, extension); } if (errors.length > 0) { throw (0, definitions_1.ErrGraphQLValidationFailed)(errors); } if ((_a = options === null || options === void 0 ? void 0 : options.validate) !== null && _a !== void 0 ? _a : true) { schema.validate(); } return schema; } exports.buildSchemaFromAST = buildSchemaFromAST; function buildNamedTypeAndDirectivesShallow(documentNode, schema, errors) { const directiveDefinitions = []; const typeDefinitions = []; const typeExtensions = []; const schemaDefinitions = []; const schemaExtensions = []; for (const definitionNode of documentNode.definitions) { switch (definitionNode.kind) { case 'OperationDefinition': case 'FragmentDefinition': errors.push(error_1.ERRORS.INVALID_GRAPHQL.err("Invalid executable definition found while building schema", { nodes: definitionNode })); continue; case 'SchemaDefinition': schemaDefinitions.push(definitionNode); schema.schemaDefinition.preserveEmptyDefinition = true; break; case 'SchemaExtension': schemaExtensions.push(definitionNode); break; case 'ScalarTypeDefinition': case 'ObjectTypeDefinition': case 'InterfaceTypeDefinition': case 'UnionTypeDefinition': case 'EnumTypeDefinition': case 'InputObjectTypeDefinition': if (introspection_1.introspectionTypeNames.includes(definitionNode.name.value)) { continue; } typeDefinitions.push(definitionNode); let type = schema.type(definitionNode.name.value); if (!type || type.isBuiltIn) { type = schema.addType((0, definitions_1.newNamedType)(withoutTrailingDefinition(definitionNode.kind), definitionNode.name.value)); } else if (type.preserveEmptyDefinition) { throw error_1.ERRORS.INVALID_GRAPHQL.err(`There can be only one type named "${definitionNode.name.value}"`); } type.preserveEmptyDefinition = true; break; case 'ScalarTypeExtension': case 'ObjectTypeExtension': case 'InterfaceTypeExtension': case 'UnionTypeExtension': case 'EnumTypeExtension': case 'InputObjectTypeExtension': if (introspection_1.introspectionTypeNames.includes(definitionNode.name.value)) { continue; } typeExtensions.push(definitionNode); const existing = schema.type(definitionNode.name.value); if (!existing) { schema.addType((0, definitions_1.newNamedType)(withoutTrailingDefinition(definitionNode.kind), definitionNode.name.value)); } else if (existing.isBuiltIn) { throw error_1.ERRORS.INVALID_GRAPHQL.err(`Cannot extend built-in type "${definitionNode.name.value}"`); } break; case 'DirectiveDefinition': directiveDefinitions.push(definitionNode); schema.addDirectiveDefinition(definitionNode.name.value); break; } } return { directiveDefinitions, typeDefinitions, typeExtensions, schemaDefinitions, schemaExtensions, }; } function withoutTrailingDefinition(str) { const endString = str.endsWith('Definition') ? 'Definition' : 'Extension'; return str.slice(0, str.length - endString.length); } function getReferencedType(node, schema) { const type = schema.type(node.name.value); if (!type) { throw error_1.ERRORS.INVALID_GRAPHQL.err(`Unknown type ${node.name.value}`, { nodes: node }); } return type; } function withNodeAttachedToError(operation, node, errors) { try { operation(); } catch (e) { const causes = (0, error_1.errorCauses)(e); if (causes) { for (const cause of causes) { const allNodes = cause.nodes ? [node, ...cause.nodes] : node; errors.push((0, error_1.withModifiedErrorNodes)(cause, allNodes)); } } else { throw e; } } } function buildSchemaDefinitionInner(schemaNode, schemaDefinition, errors, extension) { var _a, _b; for (const opTypeNode of (_a = schemaNode.operationTypes) !== null && _a !== void 0 ? _a : []) { withNodeAttachedToError(() => schemaDefinition.setRoot(opTypeNode.operation, opTypeNode.type.name.value).setOfExtension(extension), opTypeNode, errors); } schemaDefinition.sourceAST = schemaNode; if ('description' in schemaNode) { schemaDefinition.description = (_b = schemaNode.description) === null || _b === void 0 ? void 0 : _b.value; } buildAppliedDirectives(schemaNode, schemaDefinition, errors, extension); } function buildAppliedDirectives(elementNode, element, errors, extension) { var _a; for (const directive of (_a = elementNode.directives) !== null && _a !== void 0 ? _a : []) { withNodeAttachedToError(() => { if (element !== element.schema().schemaDefinition || directive.name.value === 'link' || !element.schema().blueprint.applyDirectivesAfterParsing()) { const d = element.applyDirective(directive.name.value, buildArgs(directive)); d.setOfExtension(extension); d.sourceAST = directive; } else { element.addUnappliedDirective({ extension, directive, args: buildArgs(directive), nameOrDef: directive.name.value, }); } }, directive, errors); } } function buildArgs(argumentsNode) { var _a; const args = Object.create(null); for (const argNode of (_a = argumentsNode.arguments) !== null && _a !== void 0 ? _a : []) { args[argNode.name.value] = buildValue(argNode.value); } return args; } function buildNamedTypeInner(definitionNode, type, blueprint, errors, extension) { var _a, _b, _c, _d, _e; switch (definitionNode.kind) { case 'EnumTypeDefinition': case 'EnumTypeExtension': const enumType = type; for (const enumVal of (_a = definitionNode.values) !== null && _a !== void 0 ? _a : []) { buildAppliedDirectives(enumVal, enumType.value(enumVal.name.value), errors); } break; case 'ObjectTypeDefinition': case 'ObjectTypeExtension': case 'InterfaceTypeDefinition': case 'InterfaceTypeExtension': const fieldBasedType = type; for (const fieldNode of (_b = definitionNode.fields) !== null && _b !== void 0 ? _b : []) { if (blueprint.ignoreParsedField(type, fieldNode.name.value)) { continue; } const field = fieldBasedType.addField(fieldNode.name.value); field.setOfExtension(extension); buildFieldDefinitionInner(fieldNode, field, errors); } for (const itfNode of (_c = definitionNode.interfaces) !== null && _c !== void 0 ? _c : []) { withNodeAttachedToError(() => { const itfName = itfNode.name.value; if (fieldBasedType.implementsInterface(itfName)) { throw error_1.ERRORS.INVALID_GRAPHQL.err(`Type "${type}" can only implement "${itfName}" once.`); } fieldBasedType.addImplementedInterface(itfName).setOfExtension(extension); }, itfNode, errors); } break; case 'UnionTypeDefinition': case 'UnionTypeExtension': const unionType = type; for (const namedType of (_d = definitionNode.types) !== null && _d !== void 0 ? _d : []) { withNodeAttachedToError(() => { const name = namedType.name.value; if (unionType.hasTypeMember(name)) { throw error_1.ERRORS.INVALID_GRAPHQL.err(`Union type "${unionType}" can only include type "${name}" once.`); } unionType.addType(name).setOfExtension(extension); }, namedType, errors); } break; case 'InputObjectTypeDefinition': case 'InputObjectTypeExtension': const inputObjectType = type; for (const fieldNode of (_e = definitionNode.fields) !== null && _e !== void 0 ? _e : []) { const field = inputObjectType.addField(fieldNode.name.value); field.setOfExtension(extension); buildInputFieldDefinitionInner(fieldNode, field, errors); } break; } buildAppliedDirectives(definitionNode, type, errors, extension); buildDescriptionAndSourceAST(definitionNode, type); } function buildEnumTypeValuesWithoutDirectiveApplications(definitionNode, type, extension) { var _a; const enumType = type; for (const enumVal of (_a = definitionNode.values) !== null && _a !== void 0 ? _a : []) { const v = enumType.addValue(enumVal.name.value); if (enumVal.description) { v.description = enumVal.description.value; } v.setOfExtension(extension); } buildDescriptionAndSourceAST(definitionNode, type); } function buildDescriptionAndSourceAST(definitionNode, dest) { if (definitionNode.description) { dest.description = definitionNode.description.value; } dest.sourceAST = definitionNode; } function buildFieldDefinitionInner(fieldNode, field, errors) { var _a, _b; const type = buildTypeReferenceFromAST(fieldNode.type, field.schema()); field.type = validateOutputType(type, field.coordinate, fieldNode, errors); for (const inputValueDef of (_a = fieldNode.arguments) !== null && _a !== void 0 ? _a : []) { buildArgumentDefinitionInner(inputValueDef, field.addArgument(inputValueDef.name.value), errors, true); } buildAppliedDirectives(fieldNode, field, errors); field.description = (_b = fieldNode.description) === null || _b === void 0 ? void 0 : _b.value; field.sourceAST = fieldNode; } function validateOutputType(type, what, node, errors) { if ((0, definitions_1.isOutputType)(type)) { return type; } else { errors.push(error_1.ERRORS.INVALID_GRAPHQL.err(`The type of "${what}" must be Output Type but got "${type}", a ${type.kind}.`, { nodes: node })); return undefined; } } function validateInputType(type, what, node, errors) { if ((0, definitions_1.isInputType)(type)) { return type; } else { errors.push(error_1.ERRORS.INVALID_GRAPHQL.err(`The type of "${what}" must be Input Type but got "${type}", a ${type.kind}.`, { nodes: node })); return undefined; } } function builtTypeReference(encodedType, schema) { return buildTypeReferenceFromAST((0, graphql_1.parseType)(encodedType), schema); } exports.builtTypeReference = builtTypeReference; function buildTypeReferenceFromAST(typeNode, schema) { switch (typeNode.kind) { case graphql_1.Kind.LIST_TYPE: return new definitions_1.ListType(buildTypeReferenceFromAST(typeNode.type, schema)); case graphql_1.Kind.NON_NULL_TYPE: const wrapped = buildTypeReferenceFromAST(typeNode.type, schema); if (wrapped.kind == graphql_1.Kind.NON_NULL_TYPE) { throw error_1.ERRORS.INVALID_GRAPHQL.err(`Cannot apply the non-null operator (!) twice to the same type`, { nodes: typeNode }); } return new definitions_1.NonNullType(wrapped); default: return getReferencedType(typeNode, schema); } } function buildArgumentDefinitionInner(inputNode, arg, errors, includeDirectiveApplication) { var _a; const type = buildTypeReferenceFromAST(inputNode.type, arg.schema()); arg.type = validateInputType(type, arg.coordinate, inputNode, errors); arg.defaultValue = buildValue(inputNode.defaultValue); if (includeDirectiveApplication) { buildAppliedDirectives(inputNode, arg, errors); } arg.description = (_a = inputNode.description) === null || _a === void 0 ? void 0 : _a.value; arg.sourceAST = inputNode; } function buildInputFieldDefinitionInner(fieldNode, field, errors) { var _a; const type = buildTypeReferenceFromAST(fieldNode.type, field.schema()); field.type = validateInputType(type, field.coordinate, fieldNode, errors); field.defaultValue = buildValue(fieldNode.defaultValue); buildAppliedDirectives(fieldNode, field, errors); field.description = (_a = fieldNode.description) === null || _a === void 0 ? void 0 : _a.value; field.sourceAST = fieldNode; } function buildDirectiveDefinitionInnerWithoutDirectiveApplications(directiveNode, directive, errors) { var _a; for (const inputValueDef of (_a = directiveNode.arguments) !== null && _a !== void 0 ? _a : []) { buildArgumentDefinitionInner(inputValueDef, directive.addArgument(inputValueDef.name.value), errors, false); } directive.repeatable = directiveNode.repeatable; const locations = directiveNode.locations.map(({ value }) => value); directive.addLocations(...locations); buildDescriptionAndSourceAST(directiveNode, directive); } function buildDirectiveApplicationsInDirectiveDefinition(directiveNode, directive, errors) { var _a; for (const inputValueDef of (_a = directiveNode.arguments) !== null && _a !== void 0 ? _a : []) { buildAppliedDirectives(inputValueDef, directive.argument(inputValueDef.name.value), errors); } } //# sourceMappingURL=buildSchema.js.map