UNPKG

@graphql-inspector/patch

Version:

Applies changes output from @graphql-inspect/diff

276 lines (275 loc) 14.6 kB
"use strict"; 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); }