@graphql-mesh/compose-cli
Version:
108 lines (107 loc) • 5.95 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.FatalCompositionError = void 0;
exports.validateSupergraphSdl = validateSupergraphSdl;
const graphql_1 = require("graphql");
const fusion_composition_1 = require("@graphql-mesh/fusion-composition");
const utils_1 = require("@graphql-tools/utils");
class FatalCompositionError extends Error {
constructor(message) {
super(`Fatal composition error: ${message}`);
this.name = 'FatalCompositionError';
Error.captureStackTrace(this, this.constructor);
}
}
exports.FatalCompositionError = FatalCompositionError;
function validateSupergraphSdl(supergraphSdl, subgraphs) {
const schema = (0, graphql_1.buildSchema)(supergraphSdl, {
assumeValid: true,
assumeValidSDL: true,
noLocation: true,
});
const typeMap = schema.getTypeMap();
const errors = [];
for (const typeName in typeMap) {
const type = typeMap[typeName];
if (type) {
const directives = (0, utils_1.getDirectiveExtensions)(type, schema);
if (directives?.merge) {
for (const mergeDirective of directives.merge) {
const subgraphName = mergeDirective.subgraph;
const subgraph = subgraphs.find(s => s.name === subgraphName);
if (!subgraphName) {
errors.push((0, utils_1.createGraphQLError)(`Expected @merge directive on type ${typeName} to have a subgraph argument`, {
nodes: type.astNode,
}));
continue;
}
else if (!subgraph) {
errors.push((0, utils_1.createGraphQLError)(`@merge directive on type ${typeName} references unknown subgraph ${subgraphName}`, {
nodes: type.astNode,
}));
}
continue;
}
}
if (directives?.resolveTo) {
for (const resolveToDirective of directives.resolveTo) {
const subgraphName = resolveToDirective.sourceName;
const subgraph = subgraphs.find(s => s.name === subgraphName);
if (!subgraphName) {
errors.push((0, utils_1.createGraphQLError)(`Expected @resolveTo directive on type ${typeName} to have a sourceName argument`, {
nodes: type.astNode,
}));
continue;
}
else if (!subgraph) {
errors.push((0, utils_1.createGraphQLError)(`@resolveTo directive on type ${typeName} references unknown subgraph ${subgraphName}`, {
nodes: type.astNode,
}));
continue;
}
if (resolveToDirective.sourceFieldName && resolveToDirective.sourceTypeName) {
const typeDef = subgraph.typeDefs.definitions.find(def => 'name' in def && def.name.value === resolveToDirective.sourceTypeName);
if (!typeDef) {
errors.push((0, utils_1.createGraphQLError)(`@resolveTo directive on type ${typeName} references unknown type ${resolveToDirective.sourceTypeName} in subgraph ${subgraphName}`, {
nodes: type.astNode,
}));
continue;
}
const fields = ('fields' in typeDef && typeDef.fields) || [];
const fieldName = resolveToDirective.sourceFieldName;
const fieldDef = fields.find(f => f.name.value === fieldName);
if (!fieldDef) {
const suggestions = (0, fusion_composition_1.suggestionList)(fieldName, fields.map(f => f.name.value));
const suggestionStr = suggestions.length
? ` Did you mean "${suggestions.join(' or ')}"?`
: '';
errors.push((0, utils_1.createGraphQLError)(`@resolveTo directive on type ${typeName} references unknown field ${fieldName} in subgraph ${subgraphName} ${suggestionStr}`, {
nodes: type.astNode,
}));
continue;
}
// Args validation
if (resolveToDirective.sourceArgs) {
const argOfFields = 'arguments' in fieldDef && fieldDef.arguments
? fieldDef.arguments.map(arg => arg.name.value)
: [];
for (const argName in resolveToDirective.sourceArgs) {
const argNameInField = argOfFields.find(arg => arg === argName);
if (!argNameInField) {
const suggestions = (0, fusion_composition_1.suggestionList)(argName, argOfFields);
const suggestionStr = suggestions.length
? ` Did you mean "${suggestions.join(' or ')}"?`
: '';
errors.push((0, utils_1.createGraphQLError)(`@resolveTo directive on type ${typeName} references unknown argument ${argName} in field ${fieldName} of subgraph ${subgraphName} ${suggestionStr}`, {
nodes: type.astNode,
}));
}
}
}
}
}
}
}
}
return errors;
}