Skip to content

Let explicitly resolved directive classes win in classes() - #2787

Merged
spawnia merged 6 commits into
masterfrom
disable-directives
Sep 2, 2026
Merged

Let explicitly resolved directive classes win in classes()#2787
spawnia merged 6 commits into
masterfrom
disable-directives

Conversation

@spawnia

@spawnia spawnia commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

DirectiveLocator::setResolved() already took precedence in resolve(), but classes() only scanned the namespaces, so definitions() could print a directive definition that differs from the directive that actually executes. This also makes it possible to pin a single directive name across namespaces, e.g. to keep a built-in directive that a plugin shadows.

The branch history starts from an attempt to also add DirectiveLocator::disable(), which turned out to be unsafe and was dropped: Lighthouse resolves the fields generated by @paginate, @node and federation through @field, so disabling @field broke those schemas. Users cannot know which built-ins are used internally, so a ban has to be enforced by whoever parses the hand-written schema instead.

DirectiveLocator::disable() marks a directive as non-existent: its
definition is left out of the schema and using it fails validation.
This enables enforcing project conventions that a built-in directive
would bypass.

Explicitly resolved classes now also take precedence in classes(), so
definitions() can no longer print a directive that differs from the one
that is executed.
Disabling a directive at resolution time is unsafe: Lighthouse resolves
the fields generated by @paginate, @node and federation through @field,
so disabling @field broke those schemas. Whether a built-in directive is
used internally is not something users can know, so the API cannot be
offered as it was. Restricting what may appear in a hand-written schema
belongs to whoever parses that schema.
@spawnia spawnia changed the title Allow disabling directives by name Let explicitly resolved directive classes win in classes() Sep 2, 2026
Comment thread src/Schema/DirectiveLocator.php Outdated
Comment thread CHANGELOG.md Outdated
Mutate and return the resolved classnames directly, caching the scan.
@spawnia
spawnia marked this pull request as ready for review September 2, 2026 09:16
@spawnia
spawnia requested a balanced review from Copilot September 2, 2026 09:16

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Explicit aliases can duplicate directive classes and produce invalid definitions.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Aligns directive discovery and definitions with explicitly resolved directive classes.

Changes:

  • Prioritizes setResolved() mappings during namespace scans.
  • Adds regression coverage and override documentation.
  • Updates the changelog.
File summaries
File Description
src/Schema/DirectiveLocator.php Integrates resolved classes into discovery.
tests/Unit/Schema/DirectiveLocatorTest.php Tests explicit precedence.
docs/master/custom-directives/getting-started.md Documents single-directive overrides.
CHANGELOG.md Records the behavior change.
Review details
  • Files reviewed: 4/4 changed files
  • Comments generated: 1
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/Schema/DirectiveLocator.php
setResolved() is not marked as public API, no need to document it.
@spawnia
spawnia merged commit d7d19ca into master Sep 2, 2026
93 checks passed
@spawnia
spawnia deleted the disable-directives branch September 2, 2026 10:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants