@graphql-inspector/action
Version:
GraphQL Inspector functionality for GitHub Actions
276 lines (275 loc) • 13.4 kB
JavaScript
import { Kind, parseConstValue, parseType, print, } from 'graphql';
import { AddedAttributeAlreadyExistsError, AddedAttributeCoordinateNotFoundError, AddedCoordinateAlreadyExistsError, ChangedAncestorCoordinateNotFoundError, ChangedCoordinateKindMismatchError, ChangePathMissingError, DeletedAncestorCoordinateNotFoundError, DeletedAttributeNotFoundError, ValueMismatchError, } from '../errors.js';
import { nameNode, stringNode } from '../node-templates.js';
import { deleteNamedNode, findNamedNode, getDeletedNodeOfKind, parentPath } from '../utils.js';
export function directiveAdded(change, nodeByPath, config, _context) {
if (change.path === undefined) {
config.onError(new ChangePathMissingError(change), change);
return;
}
const changedNode = nodeByPath.get(change.path);
if (!changedNode) {
const node = {
kind: Kind.DIRECTIVE_DEFINITION,
name: nameNode(change.meta.addedDirectiveName),
repeatable: change.meta.addedDirectiveRepeatable,
locations: change.meta.addedDirectiveLocations.map(l => nameNode(l)),
description: change.meta.addedDirectiveDescription
? stringNode(change.meta.addedDirectiveDescription)
: undefined,
};
nodeByPath.set(change.path, node);
return;
}
if (changedNode.kind !== Kind.DIRECTIVE_DEFINITION) {
config.onError(new ChangedCoordinateKindMismatchError(Kind.DIRECTIVE_DEFINITION, changedNode.kind), change);
return;
}
// eslint-disable-next-line eqeqeq
if (change.meta.addedDirectiveRepeatable != changedNode.repeatable) {
config.onError(new ValueMismatchError(changedNode.kind, `repeatable=${change.meta.addedDirectiveRepeatable}`, `repeatable=${changedNode.repeatable}`), change);
return;
}
if (change.meta.addedDirectiveLocations.join('|') !==
changedNode.locations.map(l => l.value).join('|')) {
config.onError(new ValueMismatchError(changedNode.kind, `locations=${change.meta.addedDirectiveLocations.join('|')}`, `locations=${changedNode.locations.map(l => l.value).join('|')}`), change);
return;
}
config.onError(new AddedCoordinateAlreadyExistsError(change.path, change.type), change);
}
export function directiveRemoved(change, nodeByPath, config, _context) {
const existing = getDeletedNodeOfKind(change, nodeByPath, Kind.DIRECTIVE_DEFINITION, config);
if (existing) {
nodeByPath.delete(change.path);
}
}
export function directiveArgumentAdded(change, nodeByPath, config, _context) {
if (!change.path) {
config.onError(new ChangePathMissingError(change), change);
return;
}
const directiveNode = nodeByPath.get(change.path);
if (!directiveNode) {
config.onError(new AddedAttributeCoordinateNotFoundError(change.path, change.type, change.meta.addedDirectiveArgumentName), change);
return;
}
if (directiveNode.kind !== Kind.DIRECTIVE_DEFINITION) {
config.onError(new ChangedCoordinateKindMismatchError(Kind.DIRECTIVE_DEFINITION, directiveNode.kind), change);
return;
}
const existingArg = findNamedNode(directiveNode.arguments, change.meta.addedDirectiveArgumentName);
if (!existingArg) {
const node = {
kind: Kind.INPUT_VALUE_DEFINITION,
name: nameNode(change.meta.addedDirectiveArgumentName),
type: parseType(change.meta.addedDirectiveArgumentType),
};
directiveNode.arguments = [
...(directiveNode.arguments ?? []),
node,
];
nodeByPath.set(`${change.path}.${change.meta.addedDirectiveArgumentName}`, node);
return;
}
const existingType = print(existingArg.type);
if (existingType !== change.meta.addedDirectiveArgumentType) {
config.onError(new ValueMismatchError(existingArg.kind, `type=${change.meta.addedDirectiveArgumentType}`, `type=${existingType}`), change);
}
const existingDefaultValue = existingArg.defaultValue
? print(existingArg.defaultValue)
: undefined;
if (change.meta.addedDirectiveDefaultValue !== existingDefaultValue) {
config.onError(new ValueMismatchError(existingArg.kind, `defaultValue=${change.meta.addedDirectiveDefaultValue}`, `defaultValue=${existingDefaultValue}`), change);
}
config.onError(new AddedAttributeAlreadyExistsError(change.path, change.type, 'arguments', change.meta.addedDirectiveArgumentName), change);
}
export function directiveArgumentRemoved(change, nodeByPath, config, _context) {
if (!change.path) {
config.onError(new ChangePathMissingError(change), change);
return;
}
const argNode = getDeletedNodeOfKind(change, nodeByPath, Kind.INPUT_VALUE_DEFINITION, config);
if (argNode) {
const directiveNode = nodeByPath.get(parentPath(change.path));
if (!directiveNode) {
config.onError(new DeletedAncestorCoordinateNotFoundError(change.path, change.type, change.meta.removedDirectiveArgumentName), change);
return;
}
if (directiveNode.kind !== Kind.DIRECTIVE_DEFINITION) {
config.onError(new ChangedCoordinateKindMismatchError(Kind.DIRECTIVE_DEFINITION, directiveNode.kind), change);
return;
}
directiveNode.arguments =
deleteNamedNode(directiveNode.arguments, change.meta.removedDirectiveArgumentName);
}
}
export function directiveLocationAdded(change, nodeByPath, config, _context) {
if (!change.path) {
config.onError(new ChangePathMissingError(change), change);
return;
}
const changedNode = nodeByPath.get(change.path);
if (!changedNode) {
config.onError(new ChangedAncestorCoordinateNotFoundError(change.path, change.type, change.meta.addedDirectiveLocation), change);
return;
}
if (changedNode.kind !== Kind.DIRECTIVE_DEFINITION) {
config.onError(new ChangedCoordinateKindMismatchError(Kind.DIRECTIVE_DEFINITION, changedNode.kind), change);
return;
}
if (changedNode.locations.some(l => l.value === change.meta.addedDirectiveLocation)) {
config.onError(new AddedAttributeAlreadyExistsError(change.path, change.type, 'locations', change.meta.addedDirectiveLocation), change);
return;
}
changedNode.locations = [
...changedNode.locations,
nameNode(change.meta.addedDirectiveLocation),
];
}
export function directiveLocationRemoved(change, nodeByPath, config, _context) {
if (!change.path) {
config.onError(new ChangePathMissingError(change), change);
return;
}
const changedNode = nodeByPath.get(change.path);
if (!changedNode) {
config.onError(new DeletedAncestorCoordinateNotFoundError(change.path, change.type, change.meta.removedDirectiveLocation), change);
return;
}
if (changedNode.kind !== Kind.DIRECTIVE_DEFINITION) {
config.onError(new ChangedCoordinateKindMismatchError(Kind.DIRECTIVE_DEFINITION, changedNode.kind), change);
return;
}
const existing = changedNode.locations.findIndex(l => l.value === change.meta.removedDirectiveLocation);
if (existing >= 0) {
changedNode.locations = changedNode.locations.toSpliced(existing, 1);
}
else {
config.onError(new DeletedAttributeNotFoundError(change.path, change.type, 'locations', change.meta.removedDirectiveLocation), change);
}
}
export function directiveDescriptionChanged(change, nodeByPath, config, _context) {
if (!change.path) {
config.onError(new ChangePathMissingError(change), change);
return;
}
const directiveNode = nodeByPath.get(change.path);
if (!directiveNode) {
config.onError(new ChangedAncestorCoordinateNotFoundError(change.path, change.type, change.meta.newDirectiveDescription), change);
return;
}
if (directiveNode.kind !== Kind.DIRECTIVE_DEFINITION) {
config.onError(new ChangedCoordinateKindMismatchError(Kind.DIRECTIVE_DEFINITION, directiveNode.kind), change);
return;
}
if ((directiveNode.description?.value ?? null) !== change.meta.oldDirectiveDescription) {
config.onError(new ValueMismatchError(Kind.STRING, change.meta.oldDirectiveDescription, directiveNode.description?.value), change);
}
directiveNode.description = change.meta.newDirectiveDescription
? stringNode(change.meta.newDirectiveDescription)
: undefined;
}
export function directiveArgumentDefaultValueChanged(change, nodeByPath, config, _context) {
if (!change.path) {
config.onError(new ChangePathMissingError(change), change);
return;
}
const argumentNode = nodeByPath.get(change.path);
if (!argumentNode) {
config.onError(new ChangedAncestorCoordinateNotFoundError(change.path, change.type, change.meta.newDirectiveArgumentDefaultValue ?? null), change);
return;
}
if (argumentNode.kind !== Kind.INPUT_VALUE_DEFINITION) {
config.onError(new ChangedCoordinateKindMismatchError(Kind.INPUT_VALUE_DEFINITION, argumentNode.kind), change);
return;
}
if ((argumentNode.defaultValue && print(argumentNode.defaultValue)) ===
change.meta.oldDirectiveArgumentDefaultValue) {
argumentNode.defaultValue = change.meta
.newDirectiveArgumentDefaultValue
? parseConstValue(change.meta.newDirectiveArgumentDefaultValue)
: undefined;
}
else {
config.onError(new ValueMismatchError(Kind.INPUT_VALUE_DEFINITION, change.meta.oldDirectiveArgumentDefaultValue, argumentNode.defaultValue && print(argumentNode.defaultValue)), change);
}
}
export function directiveArgumentDescriptionChanged(change, nodeByPath, config, _context) {
if (!change.path) {
config.onError(new ChangePathMissingError(change), change);
return;
}
const argumentNode = nodeByPath.get(change.path);
if (!argumentNode) {
config.onError(new ChangedAncestorCoordinateNotFoundError(change.path, change.type, change.meta.newDirectiveArgumentDescription), change);
return;
}
if (argumentNode.kind !== Kind.INPUT_VALUE_DEFINITION) {
config.onError(new ChangedCoordinateKindMismatchError(Kind.INPUT_VALUE_DEFINITION, argumentNode.kind), change);
return;
}
if ((argumentNode.description?.value ?? null) !== change.meta.oldDirectiveArgumentDescription) {
config.onError(new ValueMismatchError(Kind.STRING, change.meta.oldDirectiveArgumentDescription ?? undefined, argumentNode.description?.value), change);
}
argumentNode.description = change.meta
.newDirectiveArgumentDescription
? stringNode(change.meta.newDirectiveArgumentDescription)
: undefined;
}
export function directiveArgumentTypeChanged(change, nodeByPath, config, _context) {
if (!change.path) {
config.onError(new ChangePathMissingError(change), change);
return;
}
const argumentNode = nodeByPath.get(change.path);
if (!argumentNode) {
config.onError(new ChangedAncestorCoordinateNotFoundError(change.path, change.type, change.meta.newDirectiveArgumentType), change);
return;
}
if (argumentNode.kind !== Kind.INPUT_VALUE_DEFINITION) {
config.onError(new ChangedCoordinateKindMismatchError(Kind.INPUT_VALUE_DEFINITION, argumentNode.kind), change);
return;
}
if (print(argumentNode.type) !== change.meta.oldDirectiveArgumentType) {
config.onError(new ValueMismatchError(Kind.STRING, change.meta.oldDirectiveArgumentType, print(argumentNode.type)), change);
}
argumentNode.type = parseType(change.meta.newDirectiveArgumentType);
}
export function directiveRepeatableAdded(change, nodeByPath, config, _context) {
if (!change.path) {
config.onError(new ChangePathMissingError(change), change);
return;
}
const directiveNode = nodeByPath.get(change.path);
if (!directiveNode) {
config.onError(new ChangedAncestorCoordinateNotFoundError(change.path, change.type, true), change);
return;
}
if (directiveNode.kind !== Kind.DIRECTIVE_DEFINITION) {
config.onError(new ChangedCoordinateKindMismatchError(Kind.DIRECTIVE_DEFINITION, directiveNode.kind), change);
return;
}
if (directiveNode.repeatable !== false) {
config.onError(new ValueMismatchError(Kind.BOOLEAN, String(directiveNode.repeatable), 'false'), change);
}
directiveNode.repeatable = true;
}
export function directiveRepeatableRemoved(change, nodeByPath, config, _context) {
if (!change.path) {
config.onError(new ChangePathMissingError(change), change);
return;
}
const directiveNode = nodeByPath.get(change.path);
if (!directiveNode) {
config.onError(new DeletedAncestorCoordinateNotFoundError(change.path, change.type, true), change);
return;
}
if (directiveNode.kind !== Kind.DIRECTIVE_DEFINITION) {
config.onError(new ChangedCoordinateKindMismatchError(Kind.DIRECTIVE_DEFINITION, directiveNode.kind), change);
return;
}
if (directiveNode.repeatable !== true) {
config.onError(new ValueMismatchError(Kind.BOOLEAN, String(directiveNode.repeatable), 'true'), change);
}
directiveNode.repeatable = false;
}