-
Notifications
You must be signed in to change notification settings - Fork 470
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
AP-682 Strip FragmentDefinition
s in client:check
when only included in @client
fields
#1454
Conversation
These will make sure we don't break the original functionality
…nitions If we remove a client field that includes fragment definitions, we should remove the fragment definition as well if that fragment isn't reused
…tatedFields This ensures that the type passed in extends from ASTNode and then returns the same type that is passed in, which may be a more specific version of ASTNode (like DocumentNode).
…d in @client field If we spread a fragment inside of a `@client` field, we remove that fragment spread. If we don't use that fragment anywhere else then we should remove the fragment definition. It _is_ possible that a fragment is used on a @client field and non-client field if they are fragments on an interface and not and object.
83bb034
to
f04abf4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@justinanastos this is a good start, but fragments can be really tricky especially as the recurse. Happy to pair on this if you have questions about my comments!
packages/apollo-language-server/src/utilities/__tests__/graphql.test.ts
Outdated
Show resolved
Hide resolved
packages/apollo-language-server/src/utilities/__tests__/graphql.test.ts
Outdated
Show resolved
Hide resolved
@jbaxleyiii Great suggestions for new test cases and awesome explanations of what my first pass was missing. I've added the suggested test cases and another one to make sure we don't remove fragments that we didn't remove because of |
packages/apollo-language-server/src/utilities/__tests__/graphql.test.ts
Outdated
Show resolved
Hide resolved
fc4b4c9
to
32601c1
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is getting closer! I left a few more questions where a couple more complex test cases with nested behaviors may be helpful to make sure all of the work is being done the way you want it to
} | ||
|
||
// All nested fragment spreads inside of this definition are now eligible to be removed | ||
visit(ast, { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we should nest visitors here. This implementation doesn't do what I think you want it to anyway. By revisiting the root ast, instead of the specific node that you are in currently, you aren't "filtering" fragment spreads inside of this definition.
Since the visitor works depth first, you should be able to visit on FragmentDefinition
to create your list, then visit the FragmentSpread next as long as you sort the document prior to doing the work so that fragment definitions always come first
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Absolutely right.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This appears to still be nested? Why was this resolved?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm sorry about that; I have no idea. I'll figure this last piece out on Monday! Thanks again @jbaxleyiii !
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My original logic was to visit all the descendents of node
to find all fragment spreads being removed because this field was being removed as well. I wrote this to visit ast
by accident; great catch @jbaxleyiii .
I think that I do, however, want to use a nested visitor
here to flag all the fragment spreads under this node as eligible for deletion. I've added a comment to hopefully explain this. Please let me know if this is the correct way to handle this problem.
We're getting a list of all the fragment spreads and then removing all fragment spreads that aren't in the list we just created. This will never happen.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@justinanastos this looks great except for the nesting of the visitors still?
/** | ||
* Remove nodes that have zero-length selection sets | ||
* | ||
* The `ast` param must extend ASTNode. We use a genetic to indicate that this function returns the same type |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generic*
} | ||
|
||
// All nested fragment spreads inside of this definition are now eligible to be removed | ||
visit(ast, { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This appears to still be nested? Why was this resolved?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@justinanastos thanks for sticking with me for the review cycles. I really appreciate the time and effort you put into this PR! I think it is good to go as is!
For future readers looking back, another approach that we could have taken here would be to look at the overall DocumentNode
and collect 1) all fragments (inline and defined) 2) determine the relationships between them and the conditionality of that related to trimmable directives (i.e. @client
) then re-walk over the AST using the visitor to selectively remove the listed fragments and trim their selection sets. This would be more kin to an "ahead of time" style versus a "just in time" style which this PR implements. If performance ever becomes a big concern, we may need to try the AOT but I'm happy with where this solution has landed
We're getting
client:check
failures when using aFragment
in a@client
field because while the fields with@client
are stripped,Fragment
s that are nested below them are not. We now check thatFragment
s can be removed if they are only used in@client
fields.I added tests to the existing functionality on one commit, added a failing test for how I expected the method to behave, and then fixed the test. Please look at the last new test to see a reproduction.
TODO:
*Make sure changelog entries note which project(s) has been affected. See older entries for examples on what this looks like.