Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions packages/merge/src/typedefs-mergers/directives.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,14 @@ const matchValues = (a: ValueNode, b: ValueNode): boolean => {
return false;
};

const isLinkDirective = (directive: DirectiveNode): boolean => directive.name.value === 'link';
const getLinkDirectiveURL = (directive: DirectiveNode): string | undefined => {
const stringValue = isLinkDirective(directive)
? directive.arguments?.find(arg => arg.name.value === 'url')?.value
: undefined;
return stringValue?.kind === 'StringValue' ? stringValue.value : undefined;
};

const matchArguments = (a: ArgumentNode, b: ArgumentNode): boolean =>
a.name.value === b.name.value && a.value.kind === b.value.kind && matchValues(a.value, b.value);

Expand Down Expand Up @@ -124,6 +132,15 @@ export function mergeDirectives(
// if did not find a directive with this name on the result set already
result.push(directive);
} else {
if (isLinkDirective(directive) && isLinkDirective(result[firstAt])) {
const url1 = getLinkDirectiveURL(directive);
const url2 = getLinkDirectiveURL(result[firstAt]);
// if both are link directives but with different urls, do not merge them
if (url1 && url2 && url1 !== url2) {
result.push(directive);
continue;
}
}
// if not repeatable and found directive with the same name already in the result set,
// then merge the arguments of the existing directive and the new directive
const mergedArguments = mergeArguments(
Expand Down
34 changes: 33 additions & 1 deletion packages/merge/tests/merge-typedefs.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1749,6 +1749,39 @@ describe('Merge TypeDefs', () => {
expect(reformulatedGraphQL).toBeSimilarString(schemaWithDescription);
});

it('merges the directives with the same name and same arguments (@link)', () => {
const schema1 = parse(/* GraphQL */ `
extend schema
@link(
url: "https://specs.apollo.dev/federation/v2.3"
import: ["@composeDirective", "@external", "@foo"]
)
`);

const schema2 = parse(/* GraphQL */ `
extend schema
@link(
url: "https://specs.apollo.dev/federation/v2.3"
import: ["@composeDirective", "@external"]
)
@link(url: "file://foo.org/trackable/v2.3", import: ["@trackable"])
`);
const typeDefs = [schema1, schema2];
const merged = mergeTypeDefs(typeDefs);
const prettyOutput = print(merged);
const prettyExpected = print(
parse(/* GraphQL */ `
extend schema
@link(
url: "https://specs.apollo.dev/federation/v2.3"
import: ["@composeDirective", "@external", "@foo"]
)
@link(url: "file://foo.org/trackable/v2.3", import: ["@trackable"]) # unique to schema 2
`),
);
expect(prettyOutput).toBeSimilarString(prettyExpected);
});

it('merges the directives with the same name and same arguments', () => {
const directive = parse(/* GraphQL */ `
directive @link(
Expand All @@ -1762,7 +1795,6 @@ describe('Merge TypeDefs', () => {
const merged = mergeTypeDefs(typeDefs);
expect(print(merged)).toBeSimilarString(print(directive));
});

it('does not merge repeatable Federation directives without the same arguments', () => {
const ast = parse(/* GraphQL */ `
extend schema
Expand Down
Loading