Skip to content

Collect fields before generating operation classes - #144

Merged
spawnia merged 3 commits into
masterfrom
collect-fields
Oct 6, 2026
Merged

spawnia merged 3 commits into
masterfrom
collect-fields

Conversation

@spawnia

@spawnia spawnia commented Oct 3, 2026 •

Copy link
Copy Markdown
Owner

OperationGenerator merged fields while walking the document, kept consistent by a namespace stack and builder deduplication.
This collects each operation into a merged model first, then generates classes from it without traversal state.

Generated code stays byte-identical

examples/*/expected is unchanged.
Old and new code also produced identical output for a schema covering merged fields across exclusive parents, covariant interface fields, aliased __typename and repeated fragment spreads.

graphql-php has no CollectFields that codegen can reuse

ReferenceExecutor::collectFields is protected, works on one runtime type and needs runtime variables.
OverlappingFieldsCanBeMerged::getFieldsAndFragmentNames is protected and groups by static parent type.

FoldFragments and AddTypename now only shape the document sent to the server

Codegen reads the document as written and adds __typename properties itself.
#145 removes FoldFragments.

Existing quirks are kept on purpose

Child classes are keyed by response path only, so ... on A { x { foo } } ... on B { x { bar } } merges into one class.
For covariant interface fields, the type of the first occurrence wins.
Each is now a local change in FieldCollector, but changes output.

Conditional fields from https://github.com//pull/79 need one flag per field

collectFields can pass a $conditional flag down, and each CollectedField can OR in ! $conditional.
That marks fields that are always present, without counting selections.

🤖 Generated with Claude Code

FieldCollector merges the fields of each operation per response path and
concrete object type, resolving fragments itself. OperationGenerator walks
that model without traversal state, adding __typename during emission.

OperationStack and the duplicate check in ObjectLikeBuilder are gone.
FoldFragments and AddTypename now only shape the document sent to the server.

🤖 Generated with Claude Code

Copilot AI 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.

Copilot review overview

🟡 Changes recommended

Introspection fields can break code generation, and document mutation defeats the intended source/wire separation.

Review effort: Balanced
Findings: 3 Medium severity

Open (3)
What changed in this PR

Refactors operation code generation to collect merged fields before generating typed classes, replacing traversal state.

Changes:

  • Adds FieldCollector, Selection, and CollectedField.
  • Reworks operation/result class generation around collected selections.
  • Separates source and wire document parameters.
File Description
src/​Codegen/​Selection.php Models fields and nested selections.
src/​Codegen/​CollectedField.php Represents a collected response field.
src/​Codegen/​FieldCollector.php Collects and merges operation fields.
src/​Codegen/​OperationGenerator.php Generates classes from collected selections.
src/​Codegen/​Generator.php Supplies source and wire documents.
src/​Codegen/​ObjectLikeBuilder.php Removes builder-level deduplication.
src/​Codegen/​OperationStack.php Removes obsolete traversal state.

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

Comment thread src/Codegen/FieldCollector.php
Comment thread src/Codegen/FieldCollector.php Outdated
Comment thread src/Codegen/Generator.php Outdated
FoldFragments and AddTypename modify nodes in place, so codegen read the folded document.

🤖 Generated with Claude Code
@spawnia
spawnia marked this pull request as ready for review October 6, 2026 19:20
@spawnia
spawnia merged commit 0134ef2 into master Oct 6, 2026
38 checks passed
@spawnia
spawnia deleted the collect-fields branch October 6, 2026 19:24
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