dotansimha / dotansimha/graphql-code-generator
Support an incremental adoption of Fragment Masking
- Dominant language
- TypeScript
- Stars
- 11.3k
- Forks
- 1.4k
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 23
Description
### Is your feature request related to a problem? Please describe.
I recently migrated a project to `client-preset` (from `gql-tag-operations-preset`) and would like to turn on Fragment Masking for it. Unfortunately, because of existing fragments that are not using Fragment Masking, we already have a thousand errors to handle to be able to.
When you enable Fragment Masking, all fragments, and operations are automatically masked, even though not all fragments or operations use Fragment Masking.
I would like the ability to unmask fragments recursively to **support an incremental adoption of Fragment Masking**.
Also related to:
- https://github.com/dotansimha/graphql-code-generator/discussions/9308
- https://github.com/dotansimha/graphql-code-generator/discussions/9325
#### Nested Fragment: ``
```tsx
export const UserAvatarUserFragment = gql(`
fragment UserAvatarUser on User {
avatarUrl
}
`);
type UserAvatarProps = {
user: ResultOf;
};
function UserAvatar(props: UserAvatarProps) {
return ;
}
```
#### Fragment: ``
```tsx
export const UserCardUserFragment = gql(`
fragment UserCardUser on User {
id
name
...UserAvatarUserFragment
}
`);
type UserCardProps = {
user: ResultOf;
};
function UserCard(props: UserCardProps) {
return (
<>
{/* ^ Property 'avatarUrl' is missing in type */}
{/* ^ Type '"UserCardUserFragment"' is not assignable to type '"UserAvatarUserFragment"' */}
);
}
```
#### Query: ``
```tsx
export const ExampleComponentQuery = gql(`
query ExampleComponent($id: String!) {
user(id: $id) {
...UserCardUser
}
}
`);
type ExampleComponentProps = {
id: VariablesOf['id'];
};
export function ExampleComponent(props: ExampleComponentProps) {
const { loading, data } = useQuery(ExampleComponentQuery, { variables: { id: props.id } });
if (loading) {
return <>loading...;
}
if (!data?.user) {
return <>no user;
}
return ;
}
```
### Describe the solution you'd like
We could expose the following utility type: `UnmaskResultOf`.
This would check if whether we're inside an operation or directly within a fragment and then recursively flatten fragments by resolving ` $fragmentRefs` and merging them to the root fragment.
```diff
type UserCardProps = {
- user: ResultOf;
- // ^? (property) user: { __typename: "User"; id: string; name: string; ' $fragmentRefs': { ... }}
+ user: UnmaskResultOf;
+ // ^? (property) user: { __typename: "User"; id: string; name: string; avatarUrl: string }
};
```
```ts
const testUnmaskResultOf: UnmaskResultOf = {
__typename: 'Query',
user: {
__typename: 'User',
id: 'some-id',
name: 'some-name',
avatarUrl: 'some-avatar-url',
},
};
```
See the implementation on TypeScript Playground: [Link](https://www.typescriptlang.org/play?#code/C4TwDgpgBAqgzhATgQQG4ENjsfJAxRdAcwFsIA7YKAXigG8oB9R0Sc9MgLigCJdEeAbijoMWHIgA23OMEQBLckSgBfKADJ6AKCi8oAEgBmhUhWAA5DhB4B+bnwQox2fgWJlKQrSsFatraH4AYWwAE1cTDypaAAo6HSYWcAore34vXXlQmTlFIl9ddi4oWQUlXzVNeN0eA2N3MwAlCEM4W24GfjRMF0c3U0puLuccPsizVQqASg16PSNxyksydt5gsIiGz0m-AKgAUQAPDjBJCCCAexIwC-IzAEUAVyQQGm1dZgCiiHsnl4yoI9HHYEroAD5QOKJL6pNaOWqVd66ZE1OqLYDNVqrTqOEKIcJjLbAIa4jaEgZUHyg5EqKbUiHkR6SSQVXxaAD07KgAFpeXz+QLBULhSLRWLubtklAAAqICDAYDyQwgAA8ABUAHxvapQADaAGkoIooABrCAgC6GKBqgC63DVBptFVmdCp-ilADV0JJnnAAPKGdVa2gOs0Wq22tl7GDkeS3NUXACSlCQCAAxorbiqYMHITAoBBDsAKKE4CJyK8bJCTUMZtQtagLlkoNw7qgkDNC8XyKXIQka0byIYkFBE1o6w2m6EElWx7pWxB24go1K8JJMN3+lE1ck4Cq8Lm8AWiyWywxagsiZi2nZB8PEFA8NfVDPH+uFRQt2Yd5A99TdLK8qKsqKr-sifokPIwD7gANPM9QUtetQQheCFRMs1hauoYEohBUGgSihHIjGcbkAmybFog6aZuQKpej6ED+oG5i3OYTLrgARmc+7XhqfEwThhGoeiGE8IJugamBkkotJLaPr4exrhuFB-IgIBfpQP6MSq9y5vcx7dr2DAGoOprmpaUD3Ha5avCor7GYaxphhZVncCx5Bscy6BcRA+7vpu6JaXu9yOnxL7zlAbZIL4nJQAABjGJDoHAJrNHATLAAGcVGnA5AAORUMAAAW0BgIgFyQA+8jXGcUSYKRUAAO7QI1FxMqEUBFaI0DGnFaaSPIZjcmVjHynFcHNXlzJQANZqSK8haQBmIjxVpoQACIXGmjzoRcoQQONUAcY8VDNSIcqAnAeQrVdNVKoNHVLldtydUg0DJU10ChLcBWdd1UDFRcCBGjVEB1TRZYlXKAB07qQLA5BJSlaUZQGQZvGqBmnnMwlXi0N7cOgFbhVAVZKR+5AacAQVBgk3Dk92qnqYFu5BmysXipzXPc5zkrwwzn7onAaqMcAACMbwC5TLO-tmpL4psFIajFXK6AAejYfhprcsgA6LUtU8Loti-T-mC0SNPrAr5JRLmOqfMk3xpPCAmZNkvBwFcEDclkPCu5FsI8J7ZDct8fsJKIPQSNIHte9ykfiNyjxSOHbqxQAsvIcBXUo8UJy4UjZYYg2SB1MTGFckWixAHVoWYdLa+QuvFrIBtCyLsgAEym8p0sW6zVsEvg6J2wksXImrMrlZVoBQHl+fR3lOVQJB2fXcaATQ1vCQO2wgfpP7WT2MH3u+-7TuxyHYcCW6ilm+QTMd+Lkv30zVM00cJxnJc1y3A8zxqWVhyVWUANZ80CIjZKqVGKo0MFpCWtBEpQJRpITKgZP6gx-jcO4lAmZAPHqAzWWhG7N1Fkg5GMDUEBhNgjJG0D0pUPQccTBVxsH-xeKPD4SQ97FB4EzcOuggRIA6NSXeKReEH2pEfS+p9QgCORBfIOcdr7UgXjAKQx844LyTinf2Kgb7sy5JnNeudvSSHikIxARcS6lmITrQqZDIEUIYWg7utDkGULQSqDBpxzisL-rggBIBOHQkdoHfh-tLEiJRLFSeWk54MDEYo9IwgVBLyzivLOOdlDFWgIYC4zILiNWumVCqSBFSMSgBXEgAMpR5USdw8RPw4RICEEad2pQ8jCAvp08oIgRjqJjr0-Iqg8rcCyHBb4cE1FSFEY05JLsEj6O8L4IAA).
> **Warning**: Pull request with the full implementation will follow.
### Describe alternatives you've considered
_No response_
### Is your feature request related to a problem? Please describe.
_No response_
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.