UNPKG

@apollo/federation

Version:
338 lines 14.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.printBlockString = exports.printType = exports.printIntrospectionSchema = exports.printSupergraphSdl = void 0; const graphql_1 = require("graphql"); const utilities_1 = require("../utilities"); const utils_1 = require("../composition/utils"); function printSupergraphSdl(schema, graphNameToEnumValueName) { const context = { graphNameToEnumValueName, }; return printFilteredSchema(schema, (n) => !(0, graphql_1.isSpecifiedDirective)(n), isDefinedType, context); } exports.printSupergraphSdl = printSupergraphSdl; function printIntrospectionSchema(schema) { return printFilteredSchema(schema, graphql_1.isSpecifiedDirective, graphql_1.isIntrospectionType, {}); } exports.printIntrospectionSchema = printIntrospectionSchema; function isDefinedType(type) { return !(0, graphql_1.isSpecifiedScalarType)(type) && !(0, graphql_1.isIntrospectionType)(type); } function printFilteredSchema(schema, directiveFilter, typeFilter, context) { const directives = schema.getDirectives().filter(directiveFilter); const types = Object.values(schema.getTypeMap()).filter(typeFilter); return ([ printSchemaDefinition(schema), ...directives.map((directive) => printDirective(directive)), ...types.map((type) => printType(type, context)), ] .filter(Boolean) .join('\n\n') + '\n'); } function printSchemaDefinition(schema) { const operationTypes = []; const queryType = schema.getQueryType(); if (queryType) { operationTypes.push(` query: ${queryType.name}`); } const mutationType = schema.getMutationType(); if (mutationType) { operationTypes.push(` mutation: ${mutationType.name}`); } const subscriptionType = schema.getSubscriptionType(); if (subscriptionType) { operationTypes.push(` subscription: ${subscriptionType.name}`); } return (printDescription(schema) + 'schema' + printCoreDirectives(schema) + `\n{\n${operationTypes.join('\n')}\n}`); } const alwaysIncludedCoreDirectives = { core: { feature: 'https://specs.apollo.dev/core/v0.2' }, join: { feature: 'https://specs.apollo.dev/join/v0.1', purpose: 'EXECUTION' }, }; const supportedCoreDirectives = { tag: { feature: 'https://specs.apollo.dev/tag/v0.1' }, }; function printCoreDirectives(schema) { const supportedCoreDirectiveNames = Object.keys(supportedCoreDirectives); const schemaDirectiveNames = schema.getDirectives().map(({ name }) => name); const supportedCoreDirectiveNamesToInclude = schemaDirectiveNames.filter((name) => supportedCoreDirectiveNames.includes(name)); const supportedCoreDirectivesToInclude = supportedCoreDirectiveNamesToInclude.map((name) => supportedCoreDirectives[name]); return [ ...Object.values(alwaysIncludedCoreDirectives), ...supportedCoreDirectivesToInclude, ].map(({ feature, purpose }) => `\n @core(feature: ${printStringLiteral(feature)}${purpose ? `, for: ${purpose}` : ''})`); } function printType(type, context) { if ((0, graphql_1.isScalarType)(type)) { return printScalar(type); } if ((0, graphql_1.isObjectType)(type)) { return printObject(type, context); } if ((0, graphql_1.isInterfaceType)(type)) { return printInterface(type, context); } if ((0, graphql_1.isUnionType)(type)) { return printUnion(type); } if ((0, graphql_1.isEnumType)(type)) { return printEnum(type); } if ((0, graphql_1.isInputObjectType)(type)) { return printInputObject(type); } throw Error('Unexpected type: ' + type.toString()); } exports.printType = printType; function printScalar(type) { return (printDescription(type) + `scalar ${type.name}` + printSpecifiedByURL(type)); } function printImplementedInterfaces(type) { const interfaces = type.getInterfaces(); return interfaces.length ? ' implements ' + interfaces.map((i) => i.name).join(' & ') : ''; } function printObject(type, context) { return (printDescription(type) + `type ${type.name}` + printImplementedInterfaces(type) + printTypeJoinDirectives(type, context) + printKnownDirectiveUsagesOnType(type) + printFields(type, context)); } function printKnownDirectiveUsagesOnType(type) { var _a, _b, _c, _d; const tagUsages = (_d = (_c = (_b = (_a = type.extensions) === null || _a === void 0 ? void 0 : _a.federation) === null || _b === void 0 ? void 0 : _b.directiveUsages) === null || _c === void 0 ? void 0 : _c.get('tag')) !== null && _d !== void 0 ? _d : []; if (tagUsages.length === 0) return ''; return '\n ' + tagUsages.map(graphql_1.print).join('\n '); } function printTypeJoinDirectives(type, context) { var _a, _b; const metadata = (_a = type.extensions) === null || _a === void 0 ? void 0 : _a.federation; if (!metadata) return ''; const { serviceName: ownerService, keys } = metadata; if (!ownerService || !keys) return ''; const { [ownerService]: ownerKeys = [], ...restKeys } = keys; const ownerEntry = [ ownerService, ownerKeys, ]; const restEntries = Object.entries(restKeys); const shouldPrintOwner = (0, graphql_1.isObjectType)(type); const ownerGraphEnumValue = (_b = context.graphNameToEnumValueName) === null || _b === void 0 ? void 0 : _b[ownerService]; (0, utilities_1.assert)(ownerGraphEnumValue, `Unexpected enum value missing for subgraph ${ownerService}`); const joinOwnerString = shouldPrintOwner ? `\n @join__owner(graph: ${ownerGraphEnumValue})` : ''; return (joinOwnerString + [ownerEntry, ...restEntries] .map(([service, keys = []]) => keys .map((selections) => { var _a; const typeGraphEnumValue = (_a = context.graphNameToEnumValueName) === null || _a === void 0 ? void 0 : _a[service]; (0, utilities_1.assert)(typeGraphEnumValue, `Unexpected enum value missing for subgraph ${service}`); return `\n @join__type(graph: ${typeGraphEnumValue}, key: ${printStringLiteral((0, utils_1.printFieldSet)(selections))})`; }) .join('')) .join('')); } function printInterface(type, context) { return (printDescription(type) + `interface ${type.name}` + printImplementedInterfaces(type) + printTypeJoinDirectives(type, context) + printKnownDirectiveUsagesOnType(type) + printFields(type, context)); } function printUnion(type) { const types = type.getTypes(); const knownDirectiveUsages = printKnownDirectiveUsagesOnType(type); const possibleTypes = types.length ? `${knownDirectiveUsages.length ? '\n' : ' '}= ` + types.join(' | ') : ''; return (printDescription(type) + 'union ' + type.name + knownDirectiveUsages + possibleTypes); } function printEnum(type) { const values = type .getValues() .map((value, i) => printDescription(value, ' ', !i) + ' ' + value.name + printDeprecated(value.deprecationReason) + printDirectivesOnEnumValue(type, value)); return (printDescription(type) + `enum ${type.name}` + printBlock(values)); } function printDirectivesOnEnumValue(type, value) { var _a; if (type.name === "join__Graph") { return ` @join__graph(name: ${printStringLiteral((value.value.name))} url: ${printStringLiteral((_a = value.value.url) !== null && _a !== void 0 ? _a : '')})`; } return ''; } function printInputObject(type) { const fields = Object.values(type.getFields()).map((f, i) => printDescription(f, ' ', !i) + ' ' + printInputValue(f)); return printDescription(type) + `input ${type.name}` + printBlock(fields); } function printFields(type, context) { var _a, _b, _c, _d, _e, _f; const fields = Object.values(type.getFields()).map((f, i) => printDescription(f, ' ', !i) + ' ' + f.name + printArgs(f.args, ' ') + ': ' + String(f.type) + printDeprecated(f.deprecationReason) + ((0, graphql_1.isObjectType)(type) ? printJoinFieldDirectives(f, type, context) + printKnownDirectiveUsagesOnFields(f) : '')); const isEntity = Boolean((_b = (_a = type.extensions) === null || _a === void 0 ? void 0 : _a.federation) === null || _b === void 0 ? void 0 : _b.keys); const hasTags = Boolean((_f = (_e = (_d = (_c = type.extensions) === null || _c === void 0 ? void 0 : _c.federation) === null || _d === void 0 ? void 0 : _d.directiveUsages) === null || _e === void 0 ? void 0 : _e.get('tag')) === null || _f === void 0 ? void 0 : _f.length); return printBlock(fields, isEntity || hasTags); } function printJoinFieldDirectives(field, parentType, context) { var _a, _b, _c, _d; const directiveArgs = []; const fieldMetadata = (_a = field.extensions) === null || _a === void 0 ? void 0 : _a.federation; let serviceName = fieldMetadata === null || fieldMetadata === void 0 ? void 0 : fieldMetadata.serviceName; if (!serviceName && ((_b = parentType.extensions) === null || _b === void 0 ? void 0 : _b.federation).keys) { serviceName = ((_c = parentType.extensions) === null || _c === void 0 ? void 0 : _c.federation).serviceName; } if (serviceName) { const enumValue = (_d = context.graphNameToEnumValueName) === null || _d === void 0 ? void 0 : _d[serviceName]; (0, utilities_1.assert)(enumValue, `Unexpected enum value missing for subgraph ${serviceName}`); directiveArgs.push(`graph: ${enumValue}`); } const requires = fieldMetadata === null || fieldMetadata === void 0 ? void 0 : fieldMetadata.requires; if (requires && requires.length > 0) { directiveArgs.push(`requires: ${printStringLiteral((0, utils_1.printFieldSet)(requires))}`); } const provides = fieldMetadata === null || fieldMetadata === void 0 ? void 0 : fieldMetadata.provides; if (provides && provides.length > 0) { directiveArgs.push(`provides: ${printStringLiteral((0, utils_1.printFieldSet)(provides))}`); } if (directiveArgs.length < 1) return ''; return ` @join__field(${directiveArgs.join(', ')})`; } function printKnownDirectiveUsagesOnFields(field) { var _a, _b, _c; const tagUsages = (_c = (_b = (_a = field.extensions) === null || _a === void 0 ? void 0 : _a.federation) === null || _b === void 0 ? void 0 : _b.directiveUsages) === null || _c === void 0 ? void 0 : _c.get('tag'); if (!tagUsages || tagUsages.length < 1) return ''; return ` ${tagUsages .slice() .sort((a, b) => a.name.value.localeCompare(b.name.value)) .map(graphql_1.print) .join(' ')}`; } ; function printBlock(items, onNewLine) { return items.length !== 0 ? onNewLine ? '\n{\n' + items.join('\n') + '\n}' : ' {\n' + items.join('\n') + '\n}' : ''; } function printArgs(args, indentation = '') { if (args.length === 0) { return ''; } if (args.every((arg) => !arg.description)) { return '(' + args.map(printInputValue).join(', ') + ')'; } return ('(\n' + args .map((arg, i) => printDescription(arg, ' ' + indentation, !i) + ' ' + indentation + printInputValue(arg)) .join('\n') + '\n' + indentation + ')'); } function printInputValue(arg) { const defaultAST = (0, graphql_1.astFromValue)(arg.defaultValue, arg.type); let argDecl = arg.name + ': ' + String(arg.type); if (defaultAST) { argDecl += ` = ${(0, graphql_1.print)(defaultAST)}`; } return argDecl + printDeprecated(arg.deprecationReason); } function printDirective(directive) { return (printDescription(directive) + 'directive @' + directive.name + printArgs(directive.args) + (directive.isRepeatable ? ' repeatable' : '') + ' on ' + directive.locations.join(' | ')); } function printDeprecated(reason) { if (reason == null) { return ''; } if (reason !== graphql_1.DEFAULT_DEPRECATION_REASON) { const astValue = (0, graphql_1.print)({ kind: graphql_1.Kind.STRING, value: reason }); return ` @deprecated(reason: ${astValue})`; } return ' @deprecated'; } function printSpecifiedByURL(scalar) { var _a; const specifiedByURL = (_a = scalar.specifiedByUrl) !== null && _a !== void 0 ? _a : scalar.specifiedByURL; if (specifiedByURL == null) { return ''; } const astValue = (0, graphql_1.print)({ kind: graphql_1.Kind.STRING, value: specifiedByURL, }); return ` @specifiedBy(url: ${astValue})`; } function printDescription(def, indentation = '', firstInBlock = true) { const { description } = def; if (description == null) { return ''; } const preferMultipleLines = description.length > 70; const blockString = printBlockString(description, preferMultipleLines); const prefix = indentation && !firstInBlock ? '\n' + indentation : indentation; return prefix + blockString.replace(/\n/g, '\n' + indentation) + '\n'; } function printStringLiteral(value) { return JSON.stringify(value); } function printBlockString(value, preferMultipleLines = false) { const isSingleLine = !value.includes('\n'); const hasLeadingSpace = value[0] === ' ' || value[0] === '\t'; const hasTrailingQuote = value[value.length - 1] === '"'; const hasTrailingSlash = value[value.length - 1] === '\\'; const printAsMultipleLines = !isSingleLine || hasTrailingQuote || hasTrailingSlash || preferMultipleLines; let result = ''; if (printAsMultipleLines && !(isSingleLine && hasLeadingSpace)) { result += '\n'; } result += value; if (printAsMultipleLines) { result += '\n'; } return '"""' + result.replace(/"""/g, '\\"""') + '"""'; } exports.printBlockString = printBlockString; //# sourceMappingURL=printSupergraphSdl.js.map