Skip to content

Commit 97f0421

Browse files
committed
fix: link merging
1 parent aaf0fc4 commit 97f0421

File tree

2 files changed

+54
-11
lines changed

2 files changed

+54
-11
lines changed

packages/merge/src/typedefs-mergers/directives.ts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,34 @@ import {
88
import { isSome } from '@graphql-tools/utils';
99
import { Config } from './merge-typedefs.js';
1010

11+
const isLinkDirective = (directive: DirectiveNode): boolean => directive.name.value === 'link';
12+
13+
const getLinkDirectiveURL = (directive: DirectiveNode): string | undefined => {
14+
const stringValue = isLinkDirective(directive)
15+
? directive.arguments?.find(arg => arg.name.value === 'url')?.value
16+
: undefined;
17+
return stringValue?.kind === 'StringValue' ? stringValue.value : undefined;
18+
};
19+
20+
/**
21+
* Directives are considered distinct if they have different names, or, if they
22+
* are link directives with different URLs.
23+
*/
24+
const isDirectiveMetadataDistinct = (directiveA: DirectiveNode, directiveB: DirectiveNode) => {
25+
const isLinkPair = isLinkDirective(directiveA) && isLinkDirective(directiveB);
26+
return isLinkPair ? getLinkDirectiveURL(directiveA) !== getLinkDirectiveURL(directiveB) : true;
27+
};
28+
29+
const isMatchingDirective = (a: DirectiveNode, b: DirectiveNode) => a.name.value === b.name.value;
30+
1131
function directiveAlreadyExists(
1232
directivesArr: ReadonlyArray<DirectiveNode>,
1333
otherDirective: DirectiveNode,
1434
): boolean {
15-
return !!directivesArr.find(directive => directive.name.value === otherDirective.name.value);
35+
return !!directivesArr.find(directive => {
36+
const isDirectiveNameMatching = directive.name.value === otherDirective.name.value;
37+
return isDirectiveNameMatching && !isDirectiveMetadataDistinct(directive, otherDirective);
38+
});
1639
}
1740

1841
function isRepeatableDirective(
@@ -98,7 +121,7 @@ export function mergeDirectives(
98121
directiveAlreadyExists(result, directive) &&
99122
!isRepeatableDirective(directive, directives)
100123
) {
101-
const existingDirectiveIndex = result.findIndex(d => d.name.value === directive.name.value);
124+
const existingDirectiveIndex = result.findIndex(it => isMatchingDirective(it, directive));
102125
const existingDirective = result[existingDirectiveIndex];
103126
(result[existingDirectiveIndex] as any).arguments = mergeArguments(
104127
directive.arguments || [],

packages/merge/tests/merge-typedefs.spec.ts

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1704,17 +1704,37 @@ describe('Merge TypeDefs', () => {
17041704
});
17051705
expect(reformulatedGraphQL).toBeSimilarString(schemaWithDescription);
17061706
});
1707+
17071708
it('merges the directives with the same name and same arguments', () => {
1708-
const directive = parse(/* GraphQL */ `
1709-
directive @link(
1710-
url: String!
1711-
as: String
1712-
import: [link__Import]
1713-
for: link__Purpose
1714-
) on SCHEMA
1709+
const schema1 = parse(/* GraphQL */ `
1710+
extend schema
1711+
@link(
1712+
url: "https://specs.apollo.dev/federation/v2.3"
1713+
import: ["@composeDirective", "@external", "@foo"]
1714+
)
1715+
`);
1716+
1717+
const schema2 = parse(/* GraphQL */ `
1718+
extend schema
1719+
@link(
1720+
url: "https://specs.apollo.dev/federation/v2.3"
1721+
import: ["@composeDirective", "@external"]
1722+
)
1723+
@link(url: "file://foo.org/trackable/v2.3", import: ["@trackable"])
17151724
`);
1716-
const typeDefs = [directive, directive];
1725+
const typeDefs = [schema1, schema2];
17171726
const merged = mergeTypeDefs(typeDefs);
1718-
expect(print(merged)).toBeSimilarString(print(directive));
1727+
const prettyOutput = print(merged);
1728+
const prettyExpected = print(
1729+
parse(/* GraphQL */ `
1730+
extend schema
1731+
@link(
1732+
url: "https://specs.apollo.dev/federation/v2.3"
1733+
import: ["@composeDirective", "@external", "@foo"]
1734+
)
1735+
@link(url: "file://foo.org/trackable/v2.3", import: ["@trackable"]) # unique to schema 2
1736+
`),
1737+
);
1738+
expect(prettyOutput).toBeSimilarString(prettyExpected);
17191739
});
17201740
});

0 commit comments

Comments
 (0)