UNPKG

@graphql-tools/merge

Version:

A set of utils for faster development of GraphQL tools

83 lines (82 loc) 3.38 kB
import { isSome } from '@graphql-tools/utils'; function directiveAlreadyExists(directivesArr, otherDirective) { return !!directivesArr.find(directive => directive.name.value === otherDirective.name.value); } function isRepeatableDirective(directive, directives) { return !!directives?.[directive.name.value]?.repeatable; } function nameAlreadyExists(name, namesArr) { return namesArr.some(({ value }) => value === name.value); } function mergeArguments(a1, a2) { const result = [...a2]; for (const argument of a1) { const existingIndex = result.findIndex(a => a.name.value === argument.name.value); if (existingIndex > -1) { const existingArg = result[existingIndex]; if (existingArg.value.kind === 'ListValue') { const source = existingArg.value.values; const target = argument.value.values; // merge values of two lists existingArg.value.values = deduplicateLists(source, target, (targetVal, source) => { const value = targetVal.value; return !value || !source.some((sourceVal) => sourceVal.value === value); }); } else { existingArg.value = argument.value; } } else { result.push(argument); } } return result; } function deduplicateDirectives(directives, definitions) { return directives .map((directive, i, all) => { const firstAt = all.findIndex(d => d.name.value === directive.name.value); if (firstAt !== i && !isRepeatableDirective(directive, definitions)) { const dup = all[firstAt]; directive.arguments = mergeArguments(directive.arguments, dup.arguments); return null; } return directive; }) .filter(isSome); } export function mergeDirectives(d1 = [], d2 = [], config, directives) { const reverseOrder = config && config.reverseDirectives; const asNext = reverseOrder ? d1 : d2; const asFirst = reverseOrder ? d2 : d1; const result = deduplicateDirectives([...asNext], directives); for (const directive of asFirst) { if (directiveAlreadyExists(result, directive) && !isRepeatableDirective(directive, directives)) { const existingDirectiveIndex = result.findIndex(d => d.name.value === directive.name.value); const existingDirective = result[existingDirectiveIndex]; result[existingDirectiveIndex].arguments = mergeArguments(directive.arguments || [], existingDirective.arguments || []); } else { result.push(directive); } } return result; } export function mergeDirective(node, existingNode) { if (existingNode) { return { ...node, arguments: deduplicateLists(existingNode.arguments || [], node.arguments || [], (arg, existingArgs) => !nameAlreadyExists(arg.name, existingArgs.map(a => a.name))), locations: [ ...existingNode.locations, ...node.locations.filter(name => !nameAlreadyExists(name, existingNode.locations)), ], }; } return node; } function deduplicateLists(source, target, filterFn) { return source.concat(target.filter(val => filterFn(val, source))); }