fix(codegen): recursively resolve nested fragment spreads in generated documents#424
Conversation
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Complexity | 26 |
| Duplication | 8 |
NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.
|
One remaining blocker before merge: directive preservation during inline replacement. The current code replaces a named fragment spread with an inline fragment using only the fragment definition type condition and selection set. That appears to drop directives attached to the original spread. Example: a spread using Please carry the original spread directives onto the generated inline fragment and add a regression test for The rest of the PR looks aligned with #423: transitive reachability, missing nested fragment failure, cycle detection, sibling fragments, shared fragments, variable preservation, and independent operation resolution are covered. |
|
Addressed the directive preservation review comment:
|
* fix(codegen): iteratively inline nested fragment spreads AstTransformer does not recursively visit children of nodes inserted via TreeTransformerUtil.changeNode, so a single transformation pass leaves nested fragment spreads (e.g. ...MediaTitleFragment inside ...MediaCoreFragment) unresolved in the generated document. Replace the single-pass approach with an iterative loop that re-parses and re-transforms until no FragmentSpread nodes remain. The defensive invariant check is now the loop exit condition rather than a post-hoc assertion that could throw on deeply nested fragments. Follow-up to #424. * chore(ide): update Gradle project modules and Kotlin version Add all composite-build and subproject modules to the IDE Gradle project settings so they are recognised by the IDE. Update the Kotlin compiler version from 2.0.21 to 2.4.0 to match the project toolchain.
Description
Fixes #423. The codegen
FragmentResolveronly inlined fragment references directly referenced from the operation document. When a fragment transitively referenced other fragments (e.g.MediaCoreFragmentspreadsMediaTitleFragment), those nested spreads were left as unresolved...FragmentNamein the generated document, producing invalid GraphQL requests.Root Cause
flattenFragments()usedcollectReferencedNames(document)which only collected fragment spreads from the operation document itself. ThenrelevantDefinitionswas filtered to only those directly-referenced names — excluding any fragments only reachable through nested spreads inside fragment definitions.Fix (Option A — Recursive Inline)
Replaced the shallow single-pass approach with a 4-phase resolution:
computeReachableFragmentsdetectCyclesinStack/visitedover reachable fragments. Cycles at any depth are rejected.FragmentSpread→InlineFragmentusing the full transitive closure forrelevantDefinitions. AstTransformer recurses into children automatically. Directives (@include,@skip) from the original spread are preserved on the generated inline fragment.FragmentSpreadnodes remain (defensive guard).Tests
19 tests total (6 existing + 13 new):
@include(if: $enabled)@skip(if: $skip)Validation
:codegen-core:testsuite passes... on TypeName { fields }):runtime,:api, or any other moduleNotes
Types of changes