@graphql-inspector/cli
Version:
Tooling for GraphQL. Compare GraphQL Schemas, check documents, find breaking changes, find similar types.
276 lines (275 loc) • 14.6 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.directiveUsageArgumentDefinitionAdded = directiveUsageArgumentDefinitionAdded;
exports.directiveUsageArgumentDefinitionRemoved = directiveUsageArgumentDefinitionRemoved;
exports.directiveUsageEnumAdded = directiveUsageEnumAdded;
exports.directiveUsageEnumRemoved = directiveUsageEnumRemoved;
exports.directiveUsageEnumValueAdded = directiveUsageEnumValueAdded;
exports.directiveUsageEnumValueRemoved = directiveUsageEnumValueRemoved;
exports.directiveUsageFieldAdded = directiveUsageFieldAdded;
exports.directiveUsageFieldDefinitionAdded = directiveUsageFieldDefinitionAdded;
exports.directiveUsageFieldDefinitionRemoved = directiveUsageFieldDefinitionRemoved;
exports.directiveUsageFieldRemoved = directiveUsageFieldRemoved;
exports.directiveUsageInputFieldDefinitionAdded = directiveUsageInputFieldDefinitionAdded;
exports.directiveUsageInputFieldDefinitionRemoved = directiveUsageInputFieldDefinitionRemoved;
exports.directiveUsageInputObjectAdded = directiveUsageInputObjectAdded;
exports.directiveUsageInputObjectRemoved = directiveUsageInputObjectRemoved;
exports.directiveUsageInterfaceAdded = directiveUsageInterfaceAdded;
exports.directiveUsageInterfaceRemoved = directiveUsageInterfaceRemoved;
exports.directiveUsageObjectAdded = directiveUsageObjectAdded;
exports.directiveUsageObjectRemoved = directiveUsageObjectRemoved;
exports.directiveUsageScalarAdded = directiveUsageScalarAdded;
exports.directiveUsageScalarRemoved = directiveUsageScalarRemoved;
exports.directiveUsageSchemaAdded = directiveUsageSchemaAdded;
exports.directiveUsageSchemaRemoved = directiveUsageSchemaRemoved;
exports.directiveUsageUnionMemberAdded = directiveUsageUnionMemberAdded;
exports.directiveUsageUnionMemberRemoved = directiveUsageUnionMemberRemoved;
exports.directiveUsageArgumentAdded = directiveUsageArgumentAdded;
exports.directiveUsageArgumentRemoved = directiveUsageArgumentRemoved;
const graphql_1 = require("graphql");
const errors_js_1 = require("../errors.js");
const node_templates_js_1 = require("../node-templates.js");
const utils_js_1 = require("../utils.js");
/**
* Tried to find the correct instance of the directive if it's repeated.
* @note Should this should compare the arguments also to find the exact match if possible?
*/
function findNthDirective(directives, name, n) {
let lastDirective;
let count = 0;
for (const d of directives) {
// @note this nullish check is critical even though the types dont recognize it.
if (d?.name.value === name) {
lastDirective = d;
count += 1;
if (count === n) {
break;
}
}
}
return lastDirective;
}
function directiveUsageDefinitionAdded(change, nodeByPath, config, _context) {
if (!change.path) {
config.onError(new errors_js_1.ChangedCoordinateNotFoundError(graphql_1.Kind.DIRECTIVE, change.meta.addedDirectiveName), change);
return;
}
const parentNode = nodeByPath.get((0, utils_js_1.parentPath)(change.path));
if (!parentNode) {
config.onError(new errors_js_1.ChangedAncestorCoordinateNotFoundError(change.path, change.type, change.meta.addedDirectiveName), change);
return;
}
const definition = nodeByPath.get(`@${change.meta.addedDirectiveName}`);
let repeatable = false;
if (!definition) {
console.warn(`Patch cannot determine the repeatability of directive "@${change.meta.addedDirectiveName}" because it's missing a definition.`);
}
if (definition?.kind === graphql_1.Kind.DIRECTIVE_DEFINITION) {
repeatable = definition.repeatable;
}
const directiveNode = findNthDirective(parentNode?.directives ?? [], change.meta.addedDirectiveName, change.meta.directiveRepeatedTimes);
if (!repeatable && directiveNode) {
config.onError(new errors_js_1.AddedCoordinateAlreadyExistsError(change.path, change.type), change);
return;
}
const newDirective = {
kind: graphql_1.Kind.DIRECTIVE,
name: (0, node_templates_js_1.nameNode)(change.meta.addedDirectiveName),
};
parentNode.directives = [...(parentNode.directives ?? []), newDirective];
}
function schemaDirectiveUsageDefinitionAdded(change, schemaNodes, nodeByPath, config, _context) {
if (!change.path) {
config.onError(new errors_js_1.ChangedCoordinateNotFoundError(graphql_1.Kind.DIRECTIVE, change.meta.addedDirectiveName), change);
return;
}
const definition = nodeByPath.get(`@${change.meta.addedDirectiveName}`);
let repeatable = false;
if (!definition) {
console.warn(`Directive "@${change.meta.addedDirectiveName}" is missing a definition.`);
}
if (definition?.kind === graphql_1.Kind.DIRECTIVE_DEFINITION) {
repeatable = definition.repeatable;
}
const directiveAlreadyExists = schemaNodes.some(schemaNode => findNthDirective(schemaNode.directives ?? [], change.meta.addedDirectiveName, change.meta.directiveRepeatedTimes));
if (!repeatable && directiveAlreadyExists) {
config.onError(new errors_js_1.AddedAttributeAlreadyExistsError(change.path, change.type, 'directives', change.meta.addedDirectiveName), change);
return;
}
const directiveNode = {
kind: graphql_1.Kind.DIRECTIVE,
name: (0, node_templates_js_1.nameNode)(change.meta.addedDirectiveName),
};
schemaNodes[0].directives = [
...(schemaNodes[0].directives ?? []),
directiveNode,
];
}
function schemaDirectiveUsageDefinitionRemoved(change, schemaNodes, _nodeByPath, config, _context) {
let deleted = false;
for (const node of schemaNodes) {
const directiveNode = findNthDirective(node?.directives ?? [], change.meta.removedDirectiveName, change.meta.directiveRepeatedTimes);
if (directiveNode) {
node.directives = node.directives?.filter(d => d.name.value !== change.meta.removedDirectiveName);
deleted = true;
break;
}
}
if (!deleted) {
config.onError(new errors_js_1.DeletedAttributeNotFoundError(change.path ?? '', change.type, 'directives', change.meta.removedDirectiveName), change);
}
}
function directiveUsageDefinitionRemoved(change, nodeByPath, config, context) {
if (!change.path) {
config.onError(new errors_js_1.ChangePathMissingError(change), change);
return;
}
const parentNode = nodeByPath.get((0, utils_js_1.parentPath)(change.path));
if (!parentNode) {
config.onError(new errors_js_1.DeletedAncestorCoordinateNotFoundError(change.path, change.type, change.meta.removedDirectiveName), change);
return;
}
const directiveNode = findNthDirective(parentNode?.directives ?? [], change.meta.removedDirectiveName, change.meta.directiveRepeatedTimes);
if (!directiveNode) {
config.onError(new errors_js_1.DeletedAttributeNotFoundError(change.path, change.type, 'directives', change.meta.removedDirectiveName), change);
return;
}
// null the value out for filtering later. The index is important so that changes reference
// the correct DirectiveNode.
// @note the nullish check is critical here even though the types dont show it
const removedIndex = (parentNode.directives ?? []).findIndex(d => d === directiveNode);
const directiveList = [...(parentNode.directives ?? [])];
if (removedIndex !== -1) {
directiveList[removedIndex] = undefined;
}
parentNode.directives = directiveList;
context.removedDirectiveNodes.push(parentNode);
}
function directiveUsageArgumentDefinitionAdded(change, nodeByPath, config, context) {
return directiveUsageDefinitionAdded(change, nodeByPath, config, context);
}
function directiveUsageArgumentDefinitionRemoved(change, nodeByPath, config, context) {
return directiveUsageDefinitionRemoved(change, nodeByPath, config, context);
}
function directiveUsageEnumAdded(change, nodeByPath, config, context) {
return directiveUsageDefinitionAdded(change, nodeByPath, config, context);
}
function directiveUsageEnumRemoved(change, nodeByPath, config, context) {
return directiveUsageDefinitionRemoved(change, nodeByPath, config, context);
}
function directiveUsageEnumValueAdded(change, nodeByPath, config, context) {
return directiveUsageDefinitionAdded(change, nodeByPath, config, context);
}
function directiveUsageEnumValueRemoved(change, nodeByPath, config, context) {
return directiveUsageDefinitionRemoved(change, nodeByPath, config, context);
}
function directiveUsageFieldAdded(change, nodeByPath, config, context) {
return directiveUsageDefinitionAdded(change, nodeByPath, config, context);
}
function directiveUsageFieldDefinitionAdded(change, nodeByPath, config, context) {
return directiveUsageDefinitionAdded(change, nodeByPath, config, context);
}
function directiveUsageFieldDefinitionRemoved(change, nodeByPath, config, context) {
return directiveUsageDefinitionRemoved(change, nodeByPath, config, context);
}
function directiveUsageFieldRemoved(change, nodeByPath, config, context) {
return directiveUsageDefinitionRemoved(change, nodeByPath, config, context);
}
function directiveUsageInputFieldDefinitionAdded(change, nodeByPath, config, context) {
return directiveUsageDefinitionAdded(change, nodeByPath, config, context);
}
function directiveUsageInputFieldDefinitionRemoved(change, nodeByPath, config, context) {
return directiveUsageDefinitionRemoved(change, nodeByPath, config, context);
}
function directiveUsageInputObjectAdded(change, nodeByPath, config, context) {
return directiveUsageDefinitionAdded(change, nodeByPath, config, context);
}
function directiveUsageInputObjectRemoved(change, nodeByPath, config, context) {
return directiveUsageDefinitionRemoved(change, nodeByPath, config, context);
}
function directiveUsageInterfaceAdded(change, nodeByPath, config, context) {
return directiveUsageDefinitionAdded(change, nodeByPath, config, context);
}
function directiveUsageInterfaceRemoved(change, nodeByPath, config, context) {
return directiveUsageDefinitionRemoved(change, nodeByPath, config, context);
}
function directiveUsageObjectAdded(change, nodeByPath, config, context) {
return directiveUsageDefinitionAdded(change, nodeByPath, config, context);
}
function directiveUsageObjectRemoved(change, nodeByPath, config, context) {
return directiveUsageDefinitionRemoved(change, nodeByPath, config, context);
}
function directiveUsageScalarAdded(change, nodeByPath, config, context) {
return directiveUsageDefinitionAdded(change, nodeByPath, config, context);
}
function directiveUsageScalarRemoved(change, nodeByPath, config, context) {
return directiveUsageDefinitionRemoved(change, nodeByPath, config, context);
}
function directiveUsageSchemaAdded(change, schemaDefs, nodeByPath, config, context) {
return schemaDirectiveUsageDefinitionAdded(change, schemaDefs, nodeByPath, config, context);
}
function directiveUsageSchemaRemoved(change, schemaDefs, nodeByPath, config, context) {
return schemaDirectiveUsageDefinitionRemoved(change, schemaDefs, nodeByPath, config, context);
}
function directiveUsageUnionMemberAdded(change, nodeByPath, config, context) {
return directiveUsageDefinitionAdded(change, nodeByPath, config, context);
}
function directiveUsageUnionMemberRemoved(change, nodeByPath, config, context) {
return directiveUsageDefinitionRemoved(change, nodeByPath, config, context);
}
function directiveUsageArgumentAdded(change, nodeByPath, config, _context) {
if (!change.path) {
config.onError(new errors_js_1.ChangePathMissingError(change), change);
return;
}
// Must use double parentPath b/c the path is referencing the argument
const parentNode = nodeByPath.get((0, utils_js_1.parentPath)((0, utils_js_1.parentPath)(change.path)));
const directiveNode = findNthDirective(parentNode?.directives ?? [], change.meta.directiveName, change.meta.directiveRepeatedTimes);
if (!directiveNode) {
config.onError(new errors_js_1.AddedAttributeCoordinateNotFoundError(change.path, change.type, change.meta.addedArgumentName), change);
return;
}
if (directiveNode.kind !== graphql_1.Kind.DIRECTIVE) {
config.onError(new errors_js_1.ChangedCoordinateKindMismatchError(graphql_1.Kind.DIRECTIVE, directiveNode.kind), change);
return;
}
const existing = (0, utils_js_1.findNamedNode)(directiveNode.arguments, change.meta.addedArgumentName);
// "ArgumentAdded" but argument already exists.
if (existing) {
config.onError(new errors_js_1.ValueMismatchError(directiveNode.kind, null, (0, graphql_1.print)(existing.value)), change);
existing.value = (0, graphql_1.parseValue)(change.meta.addedArgumentValue);
return;
}
const argNode = {
kind: graphql_1.Kind.ARGUMENT,
name: (0, node_templates_js_1.nameNode)(change.meta.addedArgumentName),
value: (0, graphql_1.parseValue)(change.meta.addedArgumentValue),
};
directiveNode.arguments = [
...(directiveNode.arguments ?? []),
argNode,
];
nodeByPath.set(change.path, argNode);
}
function directiveUsageArgumentRemoved(change, nodeByPath, config, _context) {
if (!change.path) {
config.onError(new errors_js_1.ChangePathMissingError(change), change);
return;
}
// Must use double parentPath b/c the path is referencing the argument
const parentNode = nodeByPath.get((0, utils_js_1.parentPath)((0, utils_js_1.parentPath)(change.path)));
const directiveNode = findNthDirective(parentNode?.directives ?? [], change.meta.directiveName, change.meta.directiveRepeatedTimes);
if (!directiveNode) {
config.onError(new errors_js_1.DeletedAncestorCoordinateNotFoundError(change.path, change.type, change.meta.removedArgumentName), change);
return;
}
if (directiveNode.kind !== graphql_1.Kind.DIRECTIVE) {
config.onError(new errors_js_1.ChangedCoordinateKindMismatchError(graphql_1.Kind.DIRECTIVE, directiveNode.kind), change);
return;
}
const existing = (0, utils_js_1.findNamedNode)(directiveNode.arguments, change.meta.removedArgumentName);
if (!existing) {
config.onError(new errors_js_1.DeletedAttributeNotFoundError(change.path, change.type, 'arguments', change.meta.removedArgumentName), change);
}
directiveNode.arguments = directiveNode.arguments?.filter(a => a.name.value !== change.meta.removedArgumentName);
}