Skip to content

[graphql-tools/utils] Add graphql v17 args defaultValue support#8226

Open
eddeee888 wants to merge 18 commits into
ardatan:masterfrom
eddeee888:fix-graphql-17-args-default-value
Open

[graphql-tools/utils] Add graphql v17 args defaultValue support#8226
eddeee888 wants to merge 18 commits into
ardatan:masterfrom
eddeee888:fix-graphql-17-args-default-value

Conversation

@eddeee888

Copy link
Copy Markdown
Collaborator

Description

Whilst working on dotansimha/graphql-code-generator#10866, I saw that args default value changes how it is presented as type:

Screenshot 2026-06-03 at 11 59 41 pm

More details in the v17 migration note: https://www.graphql-js.org/upgrade-guides/v16-v17/#default-values

This PR ensures the output of the conversion from type -> AST of args defaultValue stays the same.

Type of change

  • New feature (non-breaking change which adds functionality)

How Has This Been Tested?

  • Test A
  • Test B

@changeset-bot

changeset-bot Bot commented Jun 4, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: e54830a

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 Minor
@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

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds GraphQL v17 compatibility: astFromArg now handles arg.default.literal (ConstValueNode) converting NULL/LIST/OBJECT into JS values before calling astFromValue; includes expanded Jest tests, CI matrix entry for 17.0.0-rc.0, and a changeset for a minor release.

Changes

GraphQL v17 defaultValue Support

Layer / File(s) Summary
DefaultValue conversion in astFromArg
packages/utils/src/print-schema-with-directives.ts
astFromArg prefers arg.default.literal (ConstValueNode), converts NULL/LIST/OBJECT into JS values and calls astFromValue; falls back to existing arg.defaultValue path.
CI matrix and changeset metadata
.github/workflows/tests.yml, .changeset/eager-cities-relate.md
Adds 17.0.0-rc.0 to GraphQL test matrix and updates Changeset to mark a minor release describing the new defaultValue support.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Suggested reviewers

  • ardatan
  • enisdenjo

Poem

🐰 A tiny hop for schema code,
Defaults turned from nodes to gold,
Tests stand guard through day and night,
CI hums softly — all is right,
A carrot cheer for builds that fold. 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ 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%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: adding GraphQL v17 argument defaultValue support to graphql-tools/utils.
Description check ✅ Passed The description is directly related to the changeset, explaining the motivation (GraphQL v17 changes to defaultValue representation) and the solution (ensuring consistent AST conversion across versions).
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@@ -0,0 +1,5 @@
---
'@graphql-tools/utils': minor

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I'm using minor here as supporting graphql v17 args defaultValue is a new feature (?).

Alternatively, since package.json already says peerDeps allows graphql@17 , this could be a patch.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/utils/tests/getDocumentNodeFromSchema.spec.ts`:
- Around line 4-42: Add comprehensive tests in
packages/utils/tests/getDocumentNodeFromSchema.spec.ts to cover non-string
default value types for getDocumentNodeFromSchema: add cases for INT (input: Int
= 42), FLOAT (input: Float = 3.14), BOOLEAN (input: Boolean = true), ENUM
(input: MyEnum = VALUE), LIST (input: [String] = ["a","b"]), and OBJECT (input:
InputType = { field: "value" }). For each case call
getDocumentNodeFromSchema(schema), locate the argument via
result['definitions'].find(def => def.kind ===
Kind.OBJECT_TYPE_DEFINITION)?.fields?.[0].arguments and assert the defaultValue
has the correct kind (IntValue, FloatValue, BooleanValue, EnumValue, ListValue,
ObjectValue) and appropriate value/structure (e.g. value strings for numeric
kinds, boolean true for BooleanValue, matching name for EnumValue, array of
StringValue nodes for ListValue, and matching ObjectValue fields for input
object). Ensure tests run against both v16/v17 code paths by mirroring existing
test structure and imports (including Kind).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 89d9892f-2904-4f88-9c67-bca148672e83

📥 Commits

Reviewing files that changed from the base of the PR and between df852a2 and 1ec16b9.

📒 Files selected for processing (4)
  • .changeset/eager-cities-relate.md
  • .github/workflows/tests.yml
  • packages/utils/src/print-schema-with-directives.ts
  • packages/utils/tests/getDocumentNodeFromSchema.spec.ts

Comment thread packages/utils/tests/getDocumentNodeFromSchema.spec.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
packages/utils/tests/getDocumentNodeFromSchema.spec.ts (1)

43-388: ⚡ Quick win

Add one regression case for explicit null argument defaults.

Great coverage expansion. Please add something(input: String = null): String and assert defaultValue.kind === "NullValue" so the v17 path is guarded against null-dropping regressions.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/utils/tests/getDocumentNodeFromSchema.spec.ts` around lines 43 -
388, Add a regression test in
packages/utils/tests/getDocumentNodeFromSchema.spec.ts that mirrors the other
default-value tests: build a schema with "type Query { something(input: String =
null): String }", call getDocumentNodeFromSchema(schema), extract the argument
definition from the OBJECT_TYPE_DEFINITION field (same pattern used in existing
tests), and assert that the argument's defaultValue.kind equals "NullValue"
(and/or match an inline snapshot showing kind "NullValue") to ensure null
defaults aren't dropped in the v17 path.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/utils/src/print-schema-with-directives.ts`:
- Around line 300-317: The code accesses arg.default?.literal which doesn't
exist on graphql@16's GraphQLArgument type; update astFromArg to guard/cast
before dereferencing: detect if (arg as any).default?.literal or check
Object.prototype.hasOwnProperty.call(arg, 'default') and read default via (arg
as any).default to get literal, then run convertConstValueNode on that value;
keep the rest of the conversion logic unchanged and only change the access to
use a safe cast/feature-detection for the `default` property.
- Around line 302-305: convertConstValueNode currently maps Kind.NULL to
undefined which later becomes omitted by astFromValue causing explicit null
defaults (e.g., arg.default.literal) and nested nulls to be dropped; update
convertConstValueNode so that when node.kind === Kind.NULL it returns null (not
undefined), and ensure any code paths that handle lists/objects (e.g., the
Kind.LIST branch using node.values.map(convertConstValueNode) and object
conversion) preserve null values, so the schema printer will emit "= null" and
nested nulls correctly.

---

Nitpick comments:
In `@packages/utils/tests/getDocumentNodeFromSchema.spec.ts`:
- Around line 43-388: Add a regression test in
packages/utils/tests/getDocumentNodeFromSchema.spec.ts that mirrors the other
default-value tests: build a schema with "type Query { something(input: String =
null): String }", call getDocumentNodeFromSchema(schema), extract the argument
definition from the OBJECT_TYPE_DEFINITION field (same pattern used in existing
tests), and assert that the argument's defaultValue.kind equals "NullValue"
(and/or match an inline snapshot showing kind "NullValue") to ensure null
defaults aren't dropped in the v17 path.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a433056c-d9fa-4d4c-aaea-c62ce7fed300

📥 Commits

Reviewing files that changed from the base of the PR and between 2247dc9 and 06a94c1.

📒 Files selected for processing (2)
  • packages/utils/src/print-schema-with-directives.ts
  • packages/utils/tests/getDocumentNodeFromSchema.spec.ts

Comment thread packages/utils/src/print-schema-with-directives.ts Outdated
Comment thread packages/utils/src/print-schema-with-directives.ts Outdated
Comment thread packages/executor/src/execution/values.ts Outdated
Comment thread packages/executor/src/execution/execute.ts

@eddeee888 eddeee888 Jun 10, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This mimics https://github.com/graphql/graphql-js/blob/838760cb9db4c81c5ff716b933bf9d8ddc816f0f/src/execution/AsyncWorkTracker.ts

This is so we can construct a similar info when executing resolvers

@eddeee888 eddeee888 force-pushed the fix-graphql-17-args-default-value branch from 32b6504 to 1679aeb Compare June 10, 2026 12:15
@eddeee888 eddeee888 force-pushed the fix-graphql-17-args-default-value branch from 1679aeb to df38cf6 Compare June 10, 2026 12:20
promiseAll: values => exeContext.asyncWorkTracker.promiseAllTrackOnReject(values),
track: maybePromises => exeContext.asyncWorkTracker.addValues(maybePromises),
}),
} as GraphQLResolveInfo;

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

as GraphQLResolveInfo is needed to massage type difference between graphql@17 vs below.

WIihout this earlier versions will see type errors because GraphQLResolveInfo wouldn't have getAbortSignal and getAsyncHelpers

Comment thread package.json Outdated
Comment on lines +64 to +65
"@graphql-tools/executor-common": "1.0.6",
"@graphql-tools/wrap": "11.1.16",

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

These external graphql-tools packages are required for tests to work when updating to v17:

  • @graphql-tools/batch-delegate
  • @graphql-tools/executor-common
  • @graphql-tools/wrap

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

why?

@eddeee888 eddeee888 Jun 28, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I got something like this in tests:

CombinedGraphQLErrors: Cannot use GraphQLSchema "{ __kind: Symbol(Schema), assumeValid: false, __validationErrors: [], description: undefined, extensions: {}, astNode: { kind: "SchemaDefinition", operationTypes: [Array] }, extensionASTNodes: [], _queryType: Query, _mutationType: Mutation, _subscriptionType: Subscription, _directives: [@include, @skip, @deprecated, @specifiedBy, @oneOf], _typeMap: { File: File, Query: Query, String: String, Mutation: Mutation, Subscription: Subscription, Boolean: Boolean, __Schema: __Schema, __Type: __Type, __TypeKind: __TypeKind, __Field: __Field, __InputValue: __InputValue, __EnumValue: __EnumValue, __Directive: __Directive, __DirectiveLocation: __DirectiveLocation }, _subTypeMap: {}, _implementationsMap: {} }" from another module or realm.

    Ensure that there is only one instance of "graphql" in the node_modules
    directory. If different versions of "graphql" are the dependencies of other
    relied on modules, use "resolutions" to ensure only one version is installed.

    https://yarnpkg.com/en/docs/selective-version-resolutions

    Duplicate "graphql" modules cannot be used at the same time since different
    versions may have different capabilities and behavior. The data from one
    version used in the function from another could produce confusing and
    spurious results.

But when I removed these and only run tests for the @graphql-tools/utils package, the errors don't happen 🤔

I'll remove these for now here

@eddeee888 eddeee888 force-pushed the fix-graphql-17-args-default-value branch 2 times, most recently from e647a80 to fe5e4e3 Compare June 11, 2026 15:01
@eddeee888 eddeee888 force-pushed the fix-graphql-17-args-default-value branch from fe5e4e3 to 3c1ba55 Compare June 12, 2026 10:21

@enisdenjo enisdenjo left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

some nits, otherwise looking good! great work!

Comment thread package.json Outdated
Comment on lines +64 to +65
"@graphql-tools/executor-common": "1.0.6",
"@graphql-tools/wrap": "11.1.16",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

why?

coercedValues[name] = defaultValue;
} else if (isNonNullType(argType)) {
const defaultValue = defaultValueFromType(arg);
if (defaultValue) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

truthiness check here silently drops valid defaults of 0, false, and ""

@eddeee888 eddeee888 Jun 28, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

defaultValueFromType should return AST | undefined here, so the falsy cases of 0, false, and "" will be wrapped in the AST objects.

I'll have a commit to rename the function from defaultValueFromType to defaultValueAstFromType to make it clearer

} else if (isNonNullType(argType)) {
const defaultValue = defaultValueFromType(arg);
if (defaultValue) {
coercedValues[arg.name] = defaultValue.value;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

defaultValueFromType returns two different shapes, and .value is only correct for one of them:

  • v17 { value } branch -> shim returns the raw GraphQLDefaultInput wrapper, so
    .value is the coerced runtime value
  • v17 { literal: ConstValueNode } branch -> shim returns astFromValue(...), a
    ValueNode. .value on a ValueNode is the raw AST value ("888" instead of
    888) or undefined for list/object defaults
  • graphql <17 defaultValue branch -> shim returns a ValueNode

is this expected?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Good question 🤔 let me check/write the test cases

* When runtime default value is available (in graphql@17), it'd return the object without Kind
* Otherwise, it'd return a `ValueNode`.
*/
export const defaultValueFromType = (arg: GraphQLArgument | GraphQLInputField) => {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

can we provide typedefs for the expected return value here?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The best we could do here is ValueNode | undefined for backwards compatibility, but it's a bit awkward as ConstValueNode should be used in v16 and 17 instead.

However, it exposed that the default case with value did not return a consistent interface. I updated the implementation here to keep it consistent with the other cases

* Note: `node` is supposed to be `ConstValueNode` for graphql@17 but
* it is not available in graphql@15 so we cannot import it from `graphql`
*/
const convertConstValueNode = (node: any) => {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

is this walker necessary? astFromValueUntyped already lives in this package and the codebase already uses it as the fallback in build-operation-for-field.ts. worth checking whether it (or graphql's own valueFromASTUntyped) covers this before maintaining a custom recursive converter (not sure, feel free to disregard)

max_attempts: 5
command: npm run ${{matrix.name == 'Leak' && 'test:leaks' || 'test'}} --ci

test-v17-temp: # FIXME: Gradual support for graphql@17, once every package is compatible, this should be merged back to main step

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

now ready?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Not yet unfortunately, there are a few fixes we need to do other packages e.g. @graphql-tools/executor,
My plan is to release @graphql-tools/utils first to unblock Codegen, then come back and attempt to fix the rest

Comment thread .github/workflows/tests.yml Outdated
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