Skip to content

Commit

Permalink
enhance(merge): merge directive arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
ardatan committed Feb 20, 2024
1 parent 8fbe439 commit 8880c78
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 43 deletions.
5 changes: 5 additions & 0 deletions .changeset/gold-swans-cheat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@graphql-tools/merge": patch
---

Merge directive arguments
36 changes: 9 additions & 27 deletions packages/merge/src/typedefs-mergers/directives.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
DirectiveNode,
ListValueNode,
NameNode,
print,
} from 'graphql';
import { isSome } from '@graphql-tools/utils';
import { Config } from './merge-typedefs.js';
Expand Down Expand Up @@ -113,39 +112,22 @@ export function mergeDirectives(
return result;
}

function validateInputs(
node: DirectiveDefinitionNode,
existingNode: DirectiveDefinitionNode,
): void | never {
const printedNode = print({
...node,
description: undefined,
});
const printedExistingNode = print({
...existingNode,
description: undefined,
});
// eslint-disable-next-line
const leaveInputs = new RegExp('(directive @w*d*)|( on .*$)', 'g');
const sameArguments =
printedNode.replace(leaveInputs, '') === printedExistingNode.replace(leaveInputs, '');

if (!sameArguments) {
throw new Error(
`Unable to merge GraphQL directive "${node.name.value}". \nExisting directive: \n\t${printedExistingNode} \nReceived directive: \n\t${printedNode}`,
);
}
}

export function mergeDirective(
node: DirectiveDefinitionNode,
existingNode?: DirectiveDefinitionNode,
): DirectiveDefinitionNode {
if (existingNode) {
validateInputs(node, 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)),
Expand Down
38 changes: 22 additions & 16 deletions packages/merge/tests/merge-typedefs.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -529,25 +529,31 @@ describe('Merge TypeDefs', () => {
);
});

it('should fail if inputs of the same directive are different from each other', (done: jest.DoneCallback) => {
try {
mergeTypeDefs([
`directive @id on FIELD_DEFINITION`,
`directive @id(name: String) on FIELD_DEFINITION`,
`type MyType { id: Int @id }`,
`type Query { f1: MyType }`,
]);
it('should merge args if inputs of the same directive are different from each other', () => {
const result = mergeTypeDefs([
`directive @id on FIELD_DEFINITION`,
`directive @id(name: String) on FIELD_DEFINITION`,
`type MyType { id: Int @id }`,
`type Query { f1: MyType }`,
]);

expect(stripWhitespaces(print(result))).toBe(
stripWhitespaces(/* GraphQL */ `
directive @id(name: String) on FIELD_DEFINITION
done.fail('It should have failed');
} catch (e: any) {
const msg = stripWhitespaces(e.message);
type MyType {
id: Int @id
}
expect(msg).toMatch('GraphQL directive "id"');
expect(msg).toMatch('Existing directive: directive @id on FIELD_DEFINITION');
expect(msg).toMatch('Received directive: directive @id(name: String) on FIELD_DEFINITION');
type Query {
f1: MyType
}
done();
}
schema {
query: Query
}
`),
);
});

it('should merge the same directives', () => {
Expand Down

0 comments on commit 8880c78

Please sign in to comment.