Skip to content

Conversation

@ardatan
Copy link
Owner

@ardatan ardatan commented Nov 22, 2025

Workaround for a bug in the upstream graphql-js graphql/graphql-js#4511

Use specifiedDirectives.some instead of isSpecifiedDirective to check if the directive is a
native directive

In case of overriding a native directive like @deprecated, isSpecifiedDirective only checks the name like;

isSpecifiedDirective(directive) {
  return specifiedDirectives.some(specifiedDirective => directive.name === specifiedDirective.name);
}

But we need to check the actual reference equality to avoid rewiring native directives like below;

specifiedDirectives.some(specifiedDirective => directive === specifiedDirective)

@changeset-bot
Copy link

changeset-bot bot commented Nov 22, 2025

🦋 Changeset detected

Latest commit: c52cd46

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 26 packages
Name Type
@graphql-tools/utils Patch
@graphql-tools/executor Patch
@graphql-tools/graphql-tag-pluck Patch
@graphql-tools/import Patch
@graphql-tools/links Patch
@graphql-tools/load Patch
@graphql-tools/merge Patch
@graphql-tools/mock Patch
@graphql-tools/node-require Patch
@graphql-tools/relay-operation-optimizer Patch
@graphql-tools/resolvers-composition Patch
@graphql-tools/schema Patch
@graphql-tools/apollo-engine-loader Patch
@graphql-tools/code-file-loader Patch
@graphql-tools/git-loader Patch
@graphql-tools/github-loader Patch
@graphql-tools/graphql-file-loader Patch
@graphql-tools/json-file-loader Patch
@graphql-tools/module-loader Patch
@graphql-tools/url-loader Patch
@graphql-tools/executor-apollo-link Patch
@graphql-tools/executor-envelop Patch
@graphql-tools/executor-legacy-ws Patch
@graphql-tools/executor-urql-exchange Patch
@graphql-tools/executor-yoga Patch
graphql-tools Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 22, 2025

📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes

    • Improved detection of native directives to properly handle custom directive overrides, ensuring correct directive behavior in schema operations.
  • Tests

    • Added test coverage for custom directive handling when printing executable schemas with directives.
  • Style

    • Minor formatting cleanup in schema utilities.

✏️ Tip: You can customize this high-level summary in your review settings.

Walkthrough

This PR replaces the isSpecifiedDirective helper function with explicit reference equality checks using specifiedDirectives.some() across multiple utility files to improve handling of native directive overrides. A test is added to verify schema printing with custom directives, and a minor formatting change is made.

Changes

Cohort / File(s) Change Summary
Directive Check Refactoring
packages/utils/src/print-schema-with-directives.ts, packages/utils/src/rewire.ts
Replaced isSpecifiedDirective(directive) checks with specifiedDirectives.some(specifiedDirective => specifiedDirective === directive) for reference-equality comparison; removed isSpecifiedDirective import and added specifiedDirectives import from graphql.
Test Addition
packages/schema/tests/reproductions.test.ts
New test file verifying that executing a schema with custom deprecated directive and Date scalar, then printing with directives, reproduces the original typeDefs.
Formatting
packages/utils/src/mapSchema.ts
Removed extraneous blank line after rewireTypes call.
Changeset Documentation
.changeset/jolly-drinks-sip.md
Documents the refactoring from helper-based to reference-equality-based native directive detection.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

  • Homogeneous refactoring pattern applied consistently across print-schema-with-directives.ts and rewire.ts with clear semantics (reference equality via .some())
  • Straightforward new test that validates the core behavior without complex assertions
  • Minor formatting change requires no logic review
  • Key areas: verify reference equality logic is correct in both files and test assertions are sound

Poem

🐰 No more guessing with helper calls,
We check by reference through the halls,
With .some() hopping through the array,
Native directives now know the way! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title accurately and specifically summarizes the main change: replacing isSpecifiedDirective with direct specifiedDirectives reference checking for native directive detection.
Description check ✅ Passed The description clearly explains the bug fix: replacing isSpecifiedDirective with direct reference equality checks against specifiedDirectives to prevent rewiring of native directives when overridden.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch use-specified-directive

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Contributor

💻 Website Preview

The latest changes are available as preview in: https://pr-7716.graphql-tools.pages.dev

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
packages/schema/tests/reproductions.test.ts (1)

5-27: Good test coverage for the primary use case.

The test correctly validates that a custom @deprecated directive with a different signature is preserved when printing the schema, which is the core issue this PR addresses.

Consider adding test cases for:

  1. Verifying the custom @deprecated directive actually applies its custom fields (not just that it prints correctly)
  2. Testing with other native directives like @specifiedBy, @skip, @include
  3. Validating the rewiring behavior specifically (not just schema printing)

Example additional test:

test('custom directive with native name is rewired correctly', () => {
  const typeDefs = /* GraphQL */ `
    directive @skip(if: Boolean!, metadata: String!) on FIELD
    
    type Query {
      field: String @skip(if: true, metadata: "test")
    }
  `;
  const schema = makeExecutableSchema({ typeDefs });
  const queryType = schema.getType('Query');
  // Verify custom @skip with metadata field exists
});
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5f0df20 and c52cd46.

📒 Files selected for processing (5)
  • .changeset/jolly-drinks-sip.md (1 hunks)
  • packages/schema/tests/reproductions.test.ts (1 hunks)
  • packages/utils/src/mapSchema.ts (0 hunks)
  • packages/utils/src/print-schema-with-directives.ts (1 hunks)
  • packages/utils/src/rewire.ts (2 hunks)
💤 Files with no reviewable changes (1)
  • packages/utils/src/mapSchema.ts
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-01-29T19:58:05.749Z
Learnt from: ardatan
Repo: ardatan/graphql-tools PR: 0
File: :0-0
Timestamp: 2025-01-29T19:58:05.749Z
Learning: The `isUrl` helper in graphql-tools/utils should be tested with both URL.canParse and new URL() paths, covering various URL formats (http, https, file) and invalid cases. Tests should properly mock and restore URL.canParse to ensure consistent behavior across environments.

Applied to files:

  • packages/schema/tests/reproductions.test.ts
🧬 Code graph analysis (1)
packages/schema/tests/reproductions.test.ts (2)
packages/schema/src/makeExecutableSchema.ts (1)
  • makeExecutableSchema (51-107)
packages/utils/src/print-schema-with-directives.ts (1)
  • printSchemaWithDirectives (118-124)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: Unit Test on Node 18 (windows-latest) and GraphQL v16
  • GitHub Check: Unit Test on Node 18 (ubuntu-latest) and GraphQL v15
  • GitHub Check: Unit Test on Node 24 (ubuntu-latest) and GraphQL v16
  • GitHub Check: Unit Test on Bun
  • GitHub Check: Unit Test on Node 22 (ubuntu-latest) and GraphQL v16
  • GitHub Check: Unit Test on Node 18 (ubuntu-latest) and GraphQL v16
  • GitHub Check: Full Check on GraphQL v16
  • GitHub Check: deployment
🔇 Additional comments (5)
packages/utils/src/rewire.ts (2)

26-26: LGTM: Import updated correctly.

The import change from isSpecifiedDirective to specifiedDirectives is appropriate for the new reference-based equality check.


77-79: Approve: Reference equality correctly prevents rewiring native directives.

The change from name-based comparison to reference equality (===) is complete and correctly implemented. Verification confirms:

  • isSpecifiedDirective function has been fully removed from the codebase
  • New reference-based approach using specifiedDirectives.some(specifiedDirective => specifiedDirective === directive) is properly applied in both rewire.ts (line 77) and print-schema-with-directives.ts (line 77)
  • This correctly distinguishes between native directive instances (which maintain reference equality with GraphQL's specifiedDirectives) and custom directives with native names (which are different instances and can be rewired)
.changeset/jolly-drinks-sip.md (1)

1-20: LGTM: Changeset clearly documents the fix.

The changeset accurately explains the problem (name-based comparison allowing native directive overrides) and the solution (reference equality check).

packages/utils/src/print-schema-with-directives.ts (2)

77-79: Approve: Reference equality for directive definitions.

The change correctly uses reference equality to determine whether to skip printing a directive definition. This ensures custom directives with native names (like a custom @deprecated) have their definitions included in the output.


240-244: The review comment is based on incorrect code analysis and should be disregarded.

The original analysis misunderstands the code flow. At line 240-244, the code doesn't filter out custom directives—it separates them from native ones. The custom directives are preserved in directiveNodesBesidesNativeDirectives. At line 245, the code searches for native @deprecated in the original directives array and only reconstructs it if missing (line 250). Custom @deprecated directives in extensions would not be filtered out; they'd be found and preserved.

However, there is a related but distinct issue: the code assumes any directive with name.value === 'deprecated' is the GraphQL-specified native directive, which could misidentify custom directives with that name. But this is a different concern than what the review claims.

Likely an incorrect or invalid review comment.

@ardatan ardatan marked this pull request as draft November 22, 2025 02:03
@ardatan ardatan marked this pull request as ready for review November 22, 2025 02:47
@ardatan ardatan marked this pull request as draft November 22, 2025 02:53
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