@graphql-codegen/cli@4.0.0
Major Changes
Patch Changes
-
#9449
4d9ea1a5a
Thanks @n1ru4l! - dependencies updates:- Updated dependency
graphql-config@^5.0.0
↗︎ (from^4.5.0
, independencies
)
- Updated dependency
-
#9449
4d9ea1a5a
Thanks @n1ru4l! - dependencies updates:- Updated dependency
@graphql-tools/apollo-engine-loader@^8.0.0
↗︎ (from^7.3.6
, independencies
) - Updated dependency
@graphql-tools/code-file-loader@^8.0.0
↗︎ (from^7.3.17
, independencies
) - Updated dependency
@graphql-tools/git-loader@^8.0.0
↗︎ (from^7.2.13
, independencies
) - Updated dependency
@graphql-tools/github-loader@^8.0.0
↗︎ (from^7.3.28
, independencies
) - Updated dependency
@graphql-tools/graphql-file-loader@^8.0.0
↗︎ (from^7.5.0
, independencies
) - Updated dependency
@graphql-tools/json-file-loader@^8.0.0
↗︎ (from^7.4.1
, independencies
) - Updated dependency
@graphql-tools/load@^8.0.0
↗︎ (from^7.8.0
, independencies
) - Updated dependency
@graphql-tools/prisma-loader@^8.0.0
↗︎ (from^7.2.69
, independencies
) - Updated dependency
@graphql-tools/url-loader@^8.0.0
↗︎ (from^7.17.17
, independencies
) - Updated dependency
@graphql-tools/utils@^10.0.0
↗︎ (from^9.0.0
, independencies
) - Updated dependency
cosmiconfig@^8.1.3
↗︎ (from^7.0.0
, independencies
) - Updated dependency
graphql-config@^5.0.1
↗︎ (from^4.5.0
, independencies
)
- Updated dependency
-
#9371
d431f426e
Thanks @Axxxx0n! - Fixed option ignoreNoDocuments when using graphql configs -
#9275
2a5da5894
Thanks @milesrichardson! - Trigger rebuilds in watch mode while respecting rules of precedence and negation, both in terms of global (top-level) config vs. local (per-output target) config, and in terms of watch patterns (higher priority) vs. documents/schemas (lower priority). This fixes an issue with overly-aggressive rebuilds during watch mode. -
Updated dependencies [
4d9ea1a5a
,4d9ea1a5a
,f46803a8c
,63827fabe
,bb66c2a31
]:- @graphql-codegen/core@4.0.0
- @graphql-codegen/plugin-helpers@5.0.0
@graphql-codegen/core@4.0.0
Major Changes
Patch Changes
- #9449
4d9ea1a5a
Thanks @n1ru4l! - dependencies updates:- Updated dependency
@graphql-tools/schema@^10.0.0
↗︎ (from^9.0.0
, independencies
) - Updated dependency
@graphql-tools/utils@^10.0.0
↗︎ (from^9.1.1
, independencies
)
- Updated dependency
- Updated dependencies [
4d9ea1a5a
,f46803a8c
,63827fabe
,bb66c2a31
]:- @graphql-codegen/plugin-helpers@5.0.0
@graphql-codegen/add@5.0.0
Major Changes
Patch Changes
- Updated dependencies [
4d9ea1a5a
,f46803a8c
,63827fabe
,bb66c2a31
]:- @graphql-codegen/plugin-helpers@5.0.0
@graphql-codegen/fragment-matcher@5.0.0
Major Changes
Patch Changes
- Updated dependencies [
4d9ea1a5a
,f46803a8c
,63827fabe
,bb66c2a31
]:- @graphql-codegen/plugin-helpers@5.0.0
@graphql-codegen/introspection@4.0.0
Major Changes
Patch Changes
- Updated dependencies [
4d9ea1a5a
,4d9ea1a5a
,f46803a8c
,3848a2b73
,ba84a3a27
,63827fabe
,50471e651
,5aa95aa96
,ca02ad172
,e1dc75f3c
,bb66c2a31
,5950f5a68
,5aa95aa96
]:- @graphql-codegen/plugin-helpers@5.0.0
- @graphql-codegen/visitor-plugin-common@4.0.0
@graphql-codegen/schema-ast@4.0.0
Major Changes
Patch Changes
- #9449
4d9ea1a5a
Thanks @n1ru4l! - dependencies updates:- Updated dependency
@graphql-tools/utils@^10.0.0
↗︎ (from^9.0.0
, independencies
)
- Updated dependency
- Updated dependencies [
4d9ea1a5a
,f46803a8c
,63827fabe
,bb66c2a31
]:- @graphql-codegen/plugin-helpers@5.0.0
@graphql-codegen/time@5.0.0
Major Changes
Patch Changes
- Updated dependencies [
4d9ea1a5a
,f46803a8c
,63827fabe
,bb66c2a31
]:- @graphql-codegen/plugin-helpers@5.0.0
@graphql-codegen/visitor-plugin-common@4.0.0
Major Changes
-
#9375
ba84a3a27
Thanks @eddeee888! - Implement Scalars with input/output typesIn GraphQL, Scalar types can be different for client and server. For example, given the native GraphQL ID:
- A client may send
string
ornumber
in the input - A client receives
string
in its selection set (i.e output) - A server receives
string
in the resolver (GraphQL parsesstring
ornumber
received from the client tostring
) - A server may return
string
ornumber
(GraphQL serializes the value tostring
before sending it to the client )
Currently, we represent every Scalar with only one type. This is what codegen generates as base type:
export type Scalars = { ID: string; };
Then, this is used in both input and output type e.g.
export type Book = { __typename?: 'Book'; id: Scalars['ID']; // Output's ID can be `string` 👍 }; export type QueryBookArgs = { id: Scalars['ID']; // Input's ID can be `string` or `number`. However, the type is only `string` here 👎 };
This PR extends each Scalar to have input and output:
export type Scalars = { ID: { input: string | number; output: string; }; };
Then, each input/output GraphQL type can correctly refer to the correct input/output scalar type:
export type Book = { __typename?: 'Book'; id: Scalars['ID']['output']; // Output's ID can be `string` 👍 }; export type QueryBookArgs = { id: Scalars['ID']['input']; // Input's ID can be `string` or `number` 👍 };
Note that for
typescript-resolvers
, the type of ID needs to be inverted. However, the referenced types in GraphQL input/output types should still work correctly:export type Scalars = { ID: { input: string; output: string | number; } } export type Book = { __typename?: "Book"; id: Scalars["ID"]['output']; // Resolvers can return `string` or `number` in ID fields 👍 }; export type QueryBookArgs = { id: Scalars["ID"]['input']; // Resolvers receive `string` in ID fields 👍 }; export type ResolversTypes = { ID: ID: ResolverTypeWrapper<Scalars['ID']['output']>; // Resolvers can return `string` or `number` in ID fields 👍 } export type ResolversParentTypes = { ID: Scalars['ID']['output']; // Resolvers receive `string` or `number` from parents 👍 };
Config changes:
- Scalars option can now take input/output types:
config: { scalars: { ID: { input: 'string', output: 'string | number' } } }
- If a string is given (instead of an object with input/output fields), it will be used as both input and output types:
config: { scalars: { ID: 'string'; // This means `string` will be used for both ID's input and output types } }
- BREAKING CHANGE: External module Scalar types need to be an object with input/output fields
config: { scalars: { ID: './path/to/scalar-module'; } }
If correctly, wired up, the following will be generated:
// Previously, imported `ID` type can be a primitive type, now it must be an object with input/output fields import { ID } from './path/to/scalar-module'; export type Scalars = { ID: { input: ID['input']; output: ID['output'] }; };
BREAKING CHANGE: This changes Scalar types which could be referenced in other plugins. If you are a plugin maintainer and reference Scalar, please update your plugin to use the correct input/output types.
- A client may send
-
bb66c2a31
Thanks @n1ru4l! - Require Node.js>= 16
. Drop support for Node.js 14
Minor Changes
-
#9196
3848a2b73
Thanks @beerose! - Add@defer
directive supportWhen a query includes a deferred fragment field, the server will return a partial response with the non-deferred fields first, followed by the remaining fields once they have been resolved.
Once start using the
@defer
directive in your queries, the generated code will automatically include support for the directive.// src/index.tsx import { graphql } from './gql'; const OrdersFragment = graphql(` fragment OrdersFragment on User { orders { id total } } `); const GetUserQuery = graphql(` query GetUser($id: ID!) { user(id: $id) { id name ...OrdersFragment @defer } } `);
The generated type for
GetUserQuery
will have information that the fragment is incremental, meaning it may not be available right away.// gql/graphql.ts export type GetUserQuery = { __typename?: 'Query'; id: string; name: string } & ({ __typename?: 'Query'; } & { ' $fragmentRefs'?: { OrdersFragment: Incremental<OrdersFragment> }; });
Apart from generating code that includes support for the
@defer
directive, the Codegen also exports a utility function calledisFragmentReady
. You can use it to conditionally render components based on whether the data for a deferred
fragment is available:const OrdersList = (props: { data: FragmentType<typeof OrdersFragment> }) => { const data = useFragment(OrdersFragment, props.data); return ( // render orders list ) }; function App() { const { data } = useQuery(GetUserQuery); return ( {data && ( <> {isFragmentReady(GetUserQuery, OrdersFragment, data) && <OrdersList data={data} />} </> )} ); } export default App;
-
#9339
50471e651
Thanks @AaronMoat! - Add excludeTypes config to resolversNonOptionalTypenameThis disables the adding of
__typename
in resolver types for any specified typename. This could be useful e.g. if you're wanting to enable this for all new types going forward but not do a big migration.Usage example:
const config: CodegenConfig = { schema: 'src/schema/**/*.graphql', generates: { 'src/schema/types.ts': { plugins: ['typescript', 'typescript-resolvers'], config: { resolversNonOptionalTypename: { unionMember: true, excludeTypes: ['MyType'], }, }, }, }, };
-
#9229
5aa95aa96
Thanks @eddeee888! - Use generic to simplify ResolversUnionTypesThis follows the
ResolversInterfaceTypes
's approach where theRefType
generic is used to refer back toResolversTypes
orResolversParentTypes
in cases of nested Union types -
#9304
e1dc75f3c
Thanks @esfomeado! - Added support for disabling suffixes on Enums. -
#9229
5aa95aa96
Thanks @eddeee888! - Extract interfaces to ResolversInterfaceTypes and add to resolversNonOptionalTypenameResolversInterfaceTypes
is a new type that keeps track of a GraphQL interface and its implementing types.
For example, consider this schema:
extend type Query { character(id: ID!): CharacterNode } interface CharacterNode { id: ID! } type Wizard implements CharacterNode { id: ID! screenName: String! spells: [String!]! } type Fighter implements CharacterNode { id: ID! screenName: String! powerLevel: Int! }
The generated types will look like this:
export type ResolversInterfaceTypes<RefType extends Record<string, unknown>> = { CharacterNode: Fighter | Wizard; }; export type ResolversTypes = { // other types... CharacterNode: ResolverTypeWrapper<ResolversInterfaceTypes<ResolversTypes>['CharacterNode']>; Fighter: ResolverTypeWrapper<Fighter>; Wizard: ResolverTypeWrapper<Wizard>; // other types... }; export type ResolversParentTypes = { // other types... CharacterNode: ResolversInterfaceTypes<ResolversParentTypes>['CharacterNode']; Fighter: Fighter; Wizard: Wizard; // other types... };
The
RefType
generic is used to reference back toResolversTypes
andResolversParentTypes
in some cases such as field returning a Union.resolversNonOptionalTypename
also affectsResolversInterfaceTypes
Using the schema above, if we use
resolversNonOptionalTypename
option:const config: CodegenConfig = { schema: 'src/schema/**/*.graphql', generates: { 'src/schema/types.ts': { plugins: ['typescript', 'typescript-resolvers'], config: { resolversNonOptionalTypename: true, // Or `resolversNonOptionalTypename: { interfaceImplementingType: true }` }, }, }, };
Then, the generated type looks like this:
export type ResolversInterfaceTypes<RefType extends Record<string, unknown>> = { CharacterNode: (Fighter & { __typename: 'Fighter' }) | (Wizard & { __typename: 'Wizard' }); }; export type ResolversTypes = { // other types... CharacterNode: ResolverTypeWrapper<ResolversInterfaceTypes<ResolversTypes>['CharacterNode']>; Fighter: ResolverTypeWrapper<Fighter>; Wizard: ResolverTypeWrapper<Wizard>; // other types... }; export type ResolversParentTypes = { // other types... CharacterNode: ResolversInterfaceTypes<ResolversParentTypes>['CharacterNode']; Fighter: Fighter; Wizard: Wizard; // other types... };
Patch Changes
-
#9449
4d9ea1a5a
Thanks @n1ru4l! - dependencies updates:- Updated dependency
@graphql-tools/optimize@^2.0.0
↗︎ (from^1.3.0
, independencies
) - Updated dependency
@graphql-tools/relay-operation-optimizer@^7.0.0
↗︎ (from^6.5.0
, independencies
) - Updated dependency
@graphql-tools/utils@^10.0.0
↗︎ (from^9.0.0
, independencies
)
- Updated dependency
-
#9414
ca02ad172
Thanks @beerose! - Include nested fragments in string documentMode -
#9369
5950f5a68
Thanks @asmundg! - Output valid type names with mergeFragmentTypes -
Updated dependencies [
4d9ea1a5a
,f46803a8c
,63827fabe
,bb66c2a31
]:- @graphql-codegen/plugin-helpers@5.0.0
@graphql-codegen/typescript-document-nodes@4.0.0
Major Changes
Patch Changes
- Updated dependencies [
4d9ea1a5a
,4d9ea1a5a
,f46803a8c
,3848a2b73
,ba84a3a27
,63827fabe
,50471e651
,5aa95aa96
,ca02ad172
,e1dc75f3c
,bb66c2a31
,5950f5a68
,5aa95aa96
]:- @graphql-codegen/plugin-helpers@5.0.0
- @graphql-codegen/visitor-plugin-common@4.0.0
@graphql-codegen/gql-tag-operations@4.0.0
Major Changes
Patch Changes
- #9449
4d9ea1a5a
Thanks @n1ru4l! - dependencies updates:- Updated dependency
@graphql-tools/utils@^10.0.0
↗︎ (from^9.0.0
, independencies
)
- Updated dependency
- Updated dependencies [
4d9ea1a5a
,4d9ea1a5a
,f46803a8c
,3848a2b73
,ba84a3a27
,63827fabe
,50471e651
,5aa95aa96
,ca02ad172
,e1dc75f3c
,bb66c2a31
,5950f5a68
,5aa95aa96
]:- @graphql-codegen/plugin-helpers@5.0.0
- @graphql-codegen/visitor-plugin-common@4.0.0
@graphql-codegen/typescript-operations@4.0.0
Major Changes
-
#9375
ba84a3a27
Thanks @eddeee888! - Implement Scalars with input/output typesIn GraphQL, Scalar types can be different for client and server. For example, given the native GraphQL ID:
- A client may send
string
ornumber
in the input - A client receives
string
in its selection set (i.e output) - A server receives
string
in the resolver (GraphQL parsesstring
ornumber
received from the client tostring
) - A server may return
string
ornumber
(GraphQL serializes the value tostring
before sending it to the client )
Currently, we represent every Scalar with only one type. This is what codegen generates as base type:
export type Scalars = { ID: string; };
Then, this is used in both input and output type e.g.
export type Book = { __typename?: 'Book'; id: Scalars['ID']; // Output's ID can be `string` 👍 }; export type QueryBookArgs = { id: Scalars['ID']; // Input's ID can be `string` or `number`. However, the type is only `string` here 👎 };
This PR extends each Scalar to have input and output:
export type Scalars = { ID: { input: string | number; output: string; }; };
Then, each input/output GraphQL type can correctly refer to the correct input/output scalar type:
export type Book = { __typename?: 'Book'; id: Scalars['ID']['output']; // Output's ID can be `string` 👍 }; export type QueryBookArgs = { id: Scalars['ID']['input']; // Input's ID can be `string` or `number` 👍 };
Note that for
typescript-resolvers
, the type of ID needs to be inverted. However, the referenced types in GraphQL input/output types should still work correctly:export type Scalars = { ID: { input: string; output: string | number; } } export type Book = { __typename?: "Book"; id: Scalars["ID"]['output']; // Resolvers can return `string` or `number` in ID fields 👍 }; export type QueryBookArgs = { id: Scalars["ID"]['input']; // Resolvers receive `string` in ID fields 👍 }; export type ResolversTypes = { ID: ID: ResolverTypeWrapper<Scalars['ID']['output']>; // Resolvers can return `string` or `number` in ID fields 👍 } export type ResolversParentTypes = { ID: Scalars['ID']['output']; // Resolvers receive `string` or `number` from parents 👍 };
Config changes:
- Scalars option can now take input/output types:
config: { scalars: { ID: { input: 'string', output: 'string | number' } } }
- If a string is given (instead of an object with input/output fields), it will be used as both input and output types:
config: { scalars: { ID: 'string'; // This means `string` will be used for both ID's input and output types } }
- BREAKING CHANGE: External module Scalar types need to be an object with input/output fields
config: { scalars: { ID: './path/to/scalar-module'; } }
If correctly, wired up, the following will be generated:
// Previously, imported `ID` type can be a primitive type, now it must be an object with input/output fields import { ID } from './path/to/scalar-module'; export type Scalars = { ID: { input: ID['input']; output: ID['output'] }; };
BREAKING CHANGE: This changes Scalar types which could be referenced in other plugins. If you are a plugin maintainer and reference Scalar, please update your plugin to use the correct input/output types.
- A client may send
-
bb66c2a31
Thanks @n1ru4l! - Require Node.js>= 16
. Drop support for Node.js 14
Minor Changes
-
#9196
3848a2b73
Thanks @beerose! - Add@defer
directive supportWhen a query includes a deferred fragment field, the server will return a partial response with the non-deferred fields first, followed by the remaining fields once they have been resolved.
Once start using the
@defer
directive in your queries, the generated code will automatically include support for the directive.// src/index.tsx import { graphql } from './gql'; const OrdersFragment = graphql(` fragment OrdersFragment on User { orders { id total } } `); const GetUserQuery = graphql(` query GetUser($id: ID!) { user(id: $id) { id name ...OrdersFragment @defer } } `);
The generated type for
GetUserQuery
will have information that the fragment is incremental, meaning it may not be available right away.// gql/graphql.ts export type GetUserQuery = { __typename?: 'Query'; id: string; name: string } & ({ __typename?: 'Query'; } & { ' $fragmentRefs'?: { OrdersFragment: Incremental<OrdersFragment> }; });
Apart from generating code that includes support for the
@defer
directive, the Codegen also exports a utility function calledisFragmentReady
. You can use it to conditionally render components based on whether the data for a deferred
fragment is available:const OrdersList = (props: { data: FragmentType<typeof OrdersFragment> }) => { const data = useFragment(OrdersFragment, props.data); return ( // render orders list ) }; function App() { const { data } = useQuery(GetUserQuery); return ( {data && ( <> {isFragmentReady(GetUserQuery, OrdersFragment, data) && <OrdersList data={data} />} </> )} ); } export default App;
-
#9304
e1dc75f3c
Thanks @esfomeado! - Added support for disabling suffixes on Enums.
Patch Changes
- Updated dependencies [
4d9ea1a5a
,4d9ea1a5a
,f46803a8c
,3848a2b73
,ba84a3a27
,63827fabe
,50471e651
,5aa95aa96
,ca02ad172
,e1dc75f3c
,bb66c2a31
,5950f5a68
,5aa95aa96
]:- @graphql-codegen/plugin-helpers@5.0.0
- @graphql-codegen/visitor-plugin-common@4.0.0
- @graphql-codegen/typescript@4.0.0
@graphql-codegen/typescript-resolvers@4.0.0
Major Changes
-
#9375
ba84a3a27
Thanks @eddeee888! - Implement Scalars with input/output typesIn GraphQL, Scalar types can be different for client and server. For example, given the native GraphQL ID:
- A client may send
string
ornumber
in the input - A client receives
string
in its selection set (i.e output) - A server receives
string
in the resolver (GraphQL parsesstring
ornumber
received from the client tostring
) - A server may return
string
ornumber
(GraphQL serializes the value tostring
before sending it to the client )
Currently, we represent every Scalar with only one type. This is what codegen generates as base type:
export type Scalars = { ID: string; };
Then, this is used in both input and output type e.g.
export type Book = { __typename?: 'Book'; id: Scalars['ID']; // Output's ID can be `string` 👍 }; export type QueryBookArgs = { id: Scalars['ID']; // Input's ID can be `string` or `number`. However, the type is only `string` here 👎 };
This PR extends each Scalar to have input and output:
export type Scalars = { ID: { input: string | number; output: string; }; };
Then, each input/output GraphQL type can correctly refer to the correct input/output scalar type:
export type Book = { __typename?: 'Book'; id: Scalars['ID']['output']; // Output's ID can be `string` 👍 }; export type QueryBookArgs = { id: Scalars['ID']['input']; // Input's ID can be `string` or `number` 👍 };
Note that for
typescript-resolvers
, the type of ID needs to be inverted. However, the referenced types in GraphQL input/output types should still work correctly:export type Scalars = { ID: { input: string; output: string | number; } } export type Book = { __typename?: "Book"; id: Scalars["ID"]['output']; // Resolvers can return `string` or `number` in ID fields 👍 }; export type QueryBookArgs = { id: Scalars["ID"]['input']; // Resolvers receive `string` in ID fields 👍 }; export type ResolversTypes = { ID: ID: ResolverTypeWrapper<Scalars['ID']['output']>; // Resolvers can return `string` or `number` in ID fields 👍 } export type ResolversParentTypes = { ID: Scalars['ID']['output']; // Resolvers receive `string` or `number` from parents 👍 };
Config changes:
- Scalars option can now take input/output types:
config: { scalars: { ID: { input: 'string', output: 'string | number' } } }
- If a string is given (instead of an object with input/output fields), it will be used as both input and output types:
config: { scalars: { ID: 'string'; // This means `string` will be used for both ID's input and output types } }
- BREAKING CHANGE: External module Scalar types need to be an object with input/output fields
config: { scalars: { ID: './path/to/scalar-module'; } }
If correctly, wired up, the following will be generated:
// Previously, imported `ID` type can be a primitive type, now it must be an object with input/output fields import { ID } from './path/to/scalar-module'; export type Scalars = { ID: { input: ID['input']; output: ID['output'] }; };
BREAKING CHANGE: This changes Scalar types which could be referenced in other plugins. If you are a plugin maintainer and reference Scalar, please update your plugin to use the correct input/output types.
- A client may send
-
bb66c2a31
Thanks @n1ru4l! - Require Node.js>= 16
. Drop support for Node.js 14
Minor Changes
-
#9196
3848a2b73
Thanks @beerose! - Add@defer
directive supportWhen a query includes a deferred fragment field, the server will return a partial response with the non-deferred fields first, followed by the remaining fields once they have been resolved.
Once start using the
@defer
directive in your queries, the generated code will automatically include support for the directive.// src/index.tsx import { graphql } from './gql'; const OrdersFragment = graphql(` fragment OrdersFragment on User { orders { id total } } `); const GetUserQuery = graphql(` query GetUser($id: ID!) { user(id: $id) { id name ...OrdersFragment @defer } } `);
The generated type for
GetUserQuery
will have information that the fragment is incremental, meaning it may not be available right away.// gql/graphql.ts export type GetUserQuery = { __typename?: 'Query'; id: string; name: string } & ({ __typename?: 'Query'; } & { ' $fragmentRefs'?: { OrdersFragment: Incremental<OrdersFragment> }; });
Apart from generating code that includes support for the
@defer
directive, the Codegen also exports a utility function calledisFragmentReady
. You can use it to conditionally render components based on whether the data for a deferred
fragment is available:const OrdersList = (props: { data: FragmentType<typeof OrdersFragment> }) => { const data = useFragment(OrdersFragment, props.data); return ( // render orders list ) }; function App() { const { data } = useQuery(GetUserQuery); return ( {data && ( <> {isFragmentReady(GetUserQuery, OrdersFragment, data) && <OrdersList data={data} />} </> )} ); } export default App;
-
#9339
50471e651
Thanks @AaronMoat! - Add excludeTypes config to resolversNonOptionalTypenameThis disables the adding of
__typename
in resolver types for any specified typename. This could be useful e.g. if you're wanting to enable this for all new types going forward but not do a big migration.Usage example:
const config: CodegenConfig = { schema: 'src/schema/**/*.graphql', generates: { 'src/schema/types.ts': { plugins: ['typescript', 'typescript-resolvers'], config: { resolversNonOptionalTypename: { unionMember: true, excludeTypes: ['MyType'], }, }, }, }, };
-
#9229
5aa95aa96
Thanks @eddeee888! - Use generic to simplify ResolversUnionTypesThis follows the
ResolversInterfaceTypes
's approach where theRefType
generic is used to refer back toResolversTypes
orResolversParentTypes
in cases of nested Union types -
#9304
e1dc75f3c
Thanks @esfomeado! - Added support for disabling suffixes on Enums. -
#9229
5aa95aa96
Thanks @eddeee888! - Extract interfaces to ResolversInterfaceTypes and add to resolversNonOptionalTypenameResolversInterfaceTypes
is a new type that keeps track of a GraphQL interface and its implementing types.
For example, consider this schema:
extend type Query { character(id: ID!): CharacterNode } interface CharacterNode { id: ID! } type Wizard implements CharacterNode { id: ID! screenName: String! spells: [String!]! } type Fighter implements CharacterNode { id: ID! screenName: String! powerLevel: Int! }
The generated types will look like this:
export type ResolversInterfaceTypes<RefType extends Record<string, unknown>> = { CharacterNode: Fighter | Wizard; }; export type ResolversTypes = { // other types... CharacterNode: ResolverTypeWrapper<ResolversInterfaceTypes<ResolversTypes>['CharacterNode']>; Fighter: ResolverTypeWrapper<Fighter>; Wizard: ResolverTypeWrapper<Wizard>; // other types... }; export type ResolversParentTypes = { // other types... CharacterNode: ResolversInterfaceTypes<ResolversParentTypes>['CharacterNode']; Fighter: Fighter; Wizard: Wizard; // other types... };
The
RefType
generic is used to reference back toResolversTypes
andResolversParentTypes
in some cases such as field returning a Union.resolversNonOptionalTypename
also affectsResolversInterfaceTypes
Using the schema above, if we use
resolversNonOptionalTypename
option:const config: CodegenConfig = { schema: 'src/schema/**/*.graphql', generates: { 'src/schema/types.ts': { plugins: ['typescript', 'typescript-resolvers'], config: { resolversNonOptionalTypename: true, // Or `resolversNonOptionalTypename: { interfaceImplementingType: true }` }, }, }, };
Then, the generated type looks like this:
export type ResolversInterfaceTypes<RefType extends Record<string, unknown>> = { CharacterNode: (Fighter & { __typename: 'Fighter' }) | (Wizard & { __typename: 'Wizard' }); }; export type ResolversTypes = { // other types... CharacterNode: ResolverTypeWrapper<ResolversInterfaceTypes<ResolversTypes>['CharacterNode']>; Fighter: ResolverTypeWrapper<Fighter>; Wizard: ResolverTypeWrapper<Wizard>; // other types... }; export type ResolversParentTypes = { // other types... CharacterNode: ResolversInterfaceTypes<ResolversParentTypes>['CharacterNode']; Fighter: Fighter; Wizard: Wizard; // other types... };
Patch Changes
- #9449
4d9ea1a5a
Thanks @n1ru4l! - dependencies updates:- Updated dependency
@graphql-tools/utils@^10.0.0
↗︎ (from^9.0.0
, independencies
)
- Updated dependency
- Updated dependencies [
4d9ea1a5a
,4d9ea1a5a
,f46803a8c
,3848a2b73
,ba84a3a27
,63827fabe
,50471e651
,5aa95aa96
,ca02ad172
,e1dc75f3c
,bb66c2a31
,5950f5a68
,5aa95aa96
]:- @graphql-codegen/plugin-helpers@5.0.0
- @graphql-codegen/visitor-plugin-common@4.0.0
- @graphql-codegen/typescript@4.0.0
@graphql-codegen/typed-document-node@5.0.0
Major Changes
Minor Changes
-
#9196
3848a2b73
Thanks @beerose! - Add@defer
directive supportWhen a query includes a deferred fragment field, the server will return a partial response with the non-deferred fields first, followed by the remaining fields once they have been resolved.
Once start using the
@defer
directive in your queries, the generated code will automatically include support for the directive.// src/index.tsx import { graphql } from './gql'; const OrdersFragment = graphql(` fragment OrdersFragment on User { orders { id total } } `); const GetUserQuery = graphql(` query GetUser($id: ID!) { user(id: $id) { id name ...OrdersFragment @defer } } `);
The generated type for
GetUserQuery
will have information that the fragment is incremental, meaning it may not be available right away.// gql/graphql.ts export type GetUserQuery = { __typename?: 'Query'; id: string; name: string } & ({ __typename?: 'Query'; } & { ' $fragmentRefs'?: { OrdersFragment: Incremental<OrdersFragment> }; });
Apart from generating code that includes support for the
@defer
directive, the Codegen also exports a utility function calledisFragmentReady
. You can use it to conditionally render components based on whether the data for a deferred
fragment is available:const OrdersList = (props: { data: FragmentType<typeof OrdersFragment> }) => { const data = useFragment(OrdersFragment, props.data); return ( // render orders list ) }; function App() { const { data } = useQuery(GetUserQuery); return ( {data && ( <> {isFragmentReady(GetUserQuery, OrdersFragment, data) && <OrdersList data={data} />} </> )} ); } export default App;
Patch Changes
- Updated dependencies [
4d9ea1a5a
,4d9ea1a5a
,f46803a8c
,3848a2b73
,ba84a3a27
,63827fabe
,50471e651
,5aa95aa96
,ca02ad172
,e1dc75f3c
,bb66c2a31
,5950f5a68
,5aa95aa96
]:- @graphql-codegen/plugin-helpers@5.0.0
- @graphql-codegen/visitor-plugin-common@4.0.0
@graphql-codegen/typescript@4.0.0
Major Changes
-
#9375
ba84a3a27
Thanks @eddeee888! - Implement Scalars with input/output typesIn GraphQL, Scalar types can be different for client and server. For example, given the native GraphQL ID:
- A client may send
string
ornumber
in the input - A client receives
string
in its selection set (i.e output) - A server receives
string
in the resolver (GraphQL parsesstring
ornumber
received from the client tostring
) - A server may return
string
ornumber
(GraphQL serializes the value tostring
before sending it to the client )
Currently, we represent every Scalar with only one type. This is what codegen generates as base type:
export type Scalars = { ID: string; };
Then, this is used in both input and output type e.g.
export type Book = { __typename?: 'Book'; id: Scalars['ID']; // Output's ID can be `string` 👍 }; export type QueryBookArgs = { id: Scalars['ID']; // Input's ID can be `string` or `number`. However, the type is only `string` here 👎 };
This PR extends each Scalar to have input and output:
export type Scalars = { ID: { input: string | number; output: string; }; };
Then, each input/output GraphQL type can correctly refer to the correct input/output scalar type:
export type Book = { __typename?: 'Book'; id: Scalars['ID']['output']; // Output's ID can be `string` 👍 }; export type QueryBookArgs = { id: Scalars['ID']['input']; // Input's ID can be `string` or `number` 👍 };
Note that for
typescript-resolvers
, the type of ID needs to be inverted. However, the referenced types in GraphQL input/output types should still work correctly:export type Scalars = { ID: { input: string; output: string | number; } } export type Book = { __typename?: "Book"; id: Scalars["ID"]['output']; // Resolvers can return `string` or `number` in ID fields 👍 }; export type QueryBookArgs = { id: Scalars["ID"]['input']; // Resolvers receive `string` in ID fields 👍 }; export type ResolversTypes = { ID: ID: ResolverTypeWrapper<Scalars['ID']['output']>; // Resolvers can return `string` or `number` in ID fields 👍 } export type ResolversParentTypes = { ID: Scalars['ID']['output']; // Resolvers receive `string` or `number` from parents 👍 };
Config changes:
- Scalars option can now take input/output types:
config: { scalars: { ID: { input: 'string', output: 'string | number' } } }
- If a string is given (instead of an object with input/output fields), it will be used as both input and output types:
config: { scalars: { ID: 'string'; // This means `string` will be used for both ID's input and output types } }
- BREAKING CHANGE: External module Scalar types need to be an object with input/output fields
config: { scalars: { ID: './path/to/scalar-module'; } }
If correctly, wired up, the following will be generated:
// Previously, imported `ID` type can be a primitive type, now it must be an object with input/output fields import { ID } from './path/to/scalar-module'; export type Scalars = { ID: { input: ID['input']; output: ID['output'] }; };
BREAKING CHANGE: This changes Scalar types which could be referenced in other plugins. If you are a plugin maintainer and reference Scalar, please update your plugin to use the correct input/output types.
- A client may send
-
bb66c2a31
Thanks @n1ru4l! - Require Node.js>= 16
. Drop support for Node.js 14
Minor Changes
-
#9196
3848a2b73
Thanks @beerose! - Add@defer
directive supportWhen a query includes a deferred fragment field, the server will return a partial response with the non-deferred fields first, followed by the remaining fields once they have been resolved.
Once start using the
@defer
directive in your queries, the generated code will automatically include support for the directive.// src/index.tsx import { graphql } from './gql'; const OrdersFragment = graphql(` fragment OrdersFragment on User { orders { id total } } `); const GetUserQuery = graphql(` query GetUser($id: ID!) { user(id: $id) { id name ...OrdersFragment @defer } } `);
The generated type for
GetUserQuery
will have information that the fragment is incremental, meaning it may not be available right away.// gql/graphql.ts export type GetUserQuery = { __typename?: 'Query'; id: string; name: string } & ({ __typename?: 'Query'; } & { ' $fragmentRefs'?: { OrdersFragment: Incremental<OrdersFragment> }; });
Apart from generating code that includes support for the
@defer
directive, the Codegen also exports a utility function calledisFragmentReady
. You can use it to conditionally render components based on whether the data for a deferred
fragment is available:const OrdersList = (props: { data: FragmentType<typeof OrdersFragment> }) => { const data = useFragment(OrdersFragment, props.data); return ( // render orders list ) }; function App() { const { data } = useQuery(GetUserQuery); return ( {data && ( <> {isFragmentReady(GetUserQuery, OrdersFragment, data) && <OrdersList data={data} />} </> )} ); } export default App;
-
#9304
e1dc75f3c
Thanks @esfomeado! - Added support for disabling suffixes on Enums.
Patch Changes
- Updated dependencies [
4d9ea1a5a
,4d9ea1a5a
,4d9ea1a5a
,f46803a8c
,3848a2b73
,ba84a3a27
,63827fabe
,50471e651
,5aa95aa96
,ca02ad172
,e1dc75f3c
,bb66c2a31
,5950f5a68
,5aa95aa96
]:- @graphql-codegen/plugin-helpers@5.0.0
- @graphql-codegen/schema-ast@4.0.0
- @graphql-codegen/visitor-plugin-common@4.0.0
@graphql-codegen/client-preset@4.0.0
Major Changes
Minor Changes
-
#9196
3848a2b73
Thanks @beerose! - Add@defer
directive supportWhen a query includes a deferred fragment field, the server will return a partial response with the non-deferred fields first, followed by the remaining fields once they have been resolved.
Once start using the
@defer
directive in your queries, the generated code will automatically include support for the directive.// src/index.tsx import { graphql } from './gql'; const OrdersFragment = graphql(` fragment OrdersFragment on User { orders { id total } } `); const GetUserQuery = graphql(` query GetUser($id: ID!) { user(id: $id) { id name ...OrdersFragment @defer } } `);
The generated type for
GetUserQuery
will have information that the fragment is incremental, meaning it may not be available right away.// gql/graphql.ts export type GetUserQuery = { __typename?: 'Query'; id: string; name: string } & ({ __typename?: 'Query'; } & { ' $fragmentRefs'?: { OrdersFragment: Incremental<OrdersFragment> }; });
Apart from generating code that includes support for the
@defer
directive, the Codegen also exports a utility function calledisFragmentReady
. You can use it to conditionally render components based on whether the data for a deferred
fragment is available:const OrdersList = (props: { data: FragmentType<typeof OrdersFragment> }) => { const data = useFragment(OrdersFragment, props.data); return ( // render orders list ) }; function App() { const { data } = useQuery(GetUserQuery); return ( {data && ( <> {isFragmentReady(GetUserQuery, OrdersFragment, data) && <OrdersList data={data} />} </> )} ); } export default App;
-
#9353
d7e335b58
Thanks @charpeni! - Implement the ability the specify the hash algorithm used for persisted documents viapersistedDocuments.hashAlgorithm
Patch Changes
-
#9449
4d9ea1a5a
Thanks @n1ru4l! - dependencies updates:- Updated dependency
@graphql-tools/documents@^1.0.0
↗︎ (from^0.1.0
, independencies
) - Updated dependency
@graphql-tools/utils@^10.0.0
↗︎ (from^9.0.0
, independencies
)
- Updated dependency
-
#9385
a7dda3546
Thanks @beerose! - Improve isFragmentReady utility function to work with noUncheckedIndexedAccess TSC setting -
#9196
3848a2b73
Thanks @beerose! - PassemitLegacyCommonJSImports
andisStringDocumentMode
to the client preset config -
#9414
ca02ad172
Thanks @beerose! - Include nested fragments in string documentMode -
Updated dependencies [
4d9ea1a5a
,4d9ea1a5a
,4d9ea1a5a
,f46803a8c
,3848a2b73
,ba84a3a27
,63827fabe
,50471e651
,5aa95aa96
,ca02ad172
,e1dc75f3c
,bb66c2a31
,5950f5a68
,5aa95aa96
]:- @graphql-codegen/gql-tag-operations@4.0.0
- @graphql-codegen/plugin-helpers@5.0.0
- @graphql-codegen/visitor-plugin-common@4.0.0
- @graphql-codegen/typed-document-node@5.0.0
- @graphql-codegen/typescript-operations@4.0.0
- @graphql-codegen/typescript@4.0.0
- @graphql-codegen/add@5.0.0
@graphql-codegen/graphql-modules-preset@4.0.0
Major Changes
Patch Changes
- #9449
4d9ea1a5a
Thanks @n1ru4l! - dependencies updates:- Updated dependency
@graphql-tools/utils@^10.0.0
↗︎ (from^9.0.0
, independencies
)
- Updated dependency
- Updated dependencies [
4d9ea1a5a
,4d9ea1a5a
,f46803a8c
,3848a2b73
,ba84a3a27
,63827fabe
,50471e651
,5aa95aa96
,ca02ad172
,e1dc75f3c
,bb66c2a31
,5950f5a68
,5aa95aa96
]:- @graphql-codegen/plugin-helpers@5.0.0
- @graphql-codegen/visitor-plugin-common@4.0.0
@graphql-codegen/testing@3.0.0
Major Changes
Patch Changes
- #9407
bec804225
Thanks @renovate! - dependencies updates:- Updated dependency
nock@13.3.1
↗︎ (from13.3.0
, independencies
)
- Updated dependency
- Updated dependencies [
4d9ea1a5a
,f46803a8c
,63827fabe
,bb66c2a31
]:- @graphql-codegen/plugin-helpers@5.0.0
@graphql-codegen/plugin-helpers@5.0.0
Major Changes
Patch Changes
-
#9449
4d9ea1a5a
Thanks @n1ru4l! - dependencies updates:- Updated dependency
@graphql-tools/utils@^10.0.0
↗︎ (from^9.0.0
, independencies
)
- Updated dependency
-
#9332
f46803a8c
Thanks @eddeee888! - Update GitHub loader TypeScript type and usage docs -
#9360
63827fabe
Thanks @beerose! - Add handleAsSDL property to UrlSchemaOptions type