Skip to content

Commit

Permalink
Detect composed directives without spec
Browse files Browse the repository at this point in the history
  • Loading branch information
kamilkisiela committed Dec 15, 2023
1 parent 3196317 commit 9195942
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/nasty-ligers-exercise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@theguild/federation-composition': minor
---

Detect composed directives without spec
32 changes: 32 additions & 0 deletions __tests__/subgraph/errors/DIRECTIVE_COMPOSITION_ERROR.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,37 @@ testVersions((api, version) => {
]),
}),
);

expect(
api.composeServices([
{
name: 'foo',
typeDefs: graphql`
directive @composeDirective(name: String!) repeatable on SCHEMA
directive @block on FIELD_DEFINITION
extend schema @link(url: "https://specs.apollo.dev/federation/${version}", import: ["@composeDirective"]) @composeDirective(name: "@block")
type Query {
foo: String @block
}
`,
},
]),
).toEqual(
expect.objectContaining({
errors: expect.arrayContaining([
version === 'v2.0'
? expect.any(Object)
: expect.objectContaining({
message: expect.stringContaining(
`Directive "@block" in subgraph "foo" cannot be composed because it is not a member of a core feature`,
),
extensions: expect.objectContaining({
code: 'DIRECTIVE_COMPOSITION_ERROR',
}),
}),
]),
}),
);
});
});
24 changes: 24 additions & 0 deletions src/subgraph/validation/rules/elements/compose-directive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,30 @@ export function ComposeDirectiveRules(context: SubgraphValidationContext): ASTVi
const matchingDirective = definedDirectives.find(directive => directive.name.value === name);

if (matchingDirective) {
// check if it has a linked spec
const hasSpec = context.stateBuilder.state.links.some(link =>
link.imports.some(
im =>
im.kind === 'directive' &&
(im.alias ? im.alias.replace(/^@/, '') === name : im.name.replace(/^@/, '') === name),
),
);

if (!hasSpec) {
context.reportError(
new GraphQLError(
`Directive "@${name}" in subgraph "${context.getSubgraphName()}" cannot be composed because it is not a member of a core feature`,
{
extensions: {
code: 'DIRECTIVE_COMPOSITION_ERROR',
subgraphName: context.getSubgraphName(),
},
},
),
);
return;
}

context.stateBuilder.directive.setComposed(matchingDirective.name.value);
context.stateBuilder.composedDirectives.add(matchingDirective.name.value);
} else {
Expand Down

0 comments on commit 9195942

Please sign in to comment.