diff --git a/.changeset/every-rooms-camp.md b/.changeset/every-rooms-camp.md new file mode 100644 index 00000000000..89938d2d564 --- /dev/null +++ b/.changeset/every-rooms-camp.md @@ -0,0 +1,9 @@ +--- +'@graphql-codegen/visitor-plugin-common': major +'@graphql-codegen/typescript-operations': major +'@graphql-codegen/typescript': major +'@graphql-codegen/typescript-resolvers': major +'@graphql-codegen/client-preset': major +--- + +BREAKING CHANGE: make `unknown` instead of `any` the default custom scalar type diff --git a/dev-test/gql-tag-operations/gql/gql.ts b/dev-test/gql-tag-operations/gql/gql.ts index 0c2e0dfeb12..966c8b09699 100644 --- a/dev-test/gql-tag-operations/gql/gql.ts +++ b/dev-test/gql-tag-operations/gql/gql.ts @@ -15,12 +15,12 @@ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/ */ type Documents = { '\n query Foo {\n Tweets {\n id\n }\n }\n': typeof types.FooDocument; - '\n fragment Lel on Tweet {\n id\n body\n }\n': typeof types.LelFragmentDoc; + '\n fragment Lel on Tweet {\n id\n body\n date\n }\n': typeof types.LelFragmentDoc; '\n query Bar {\n Tweets {\n ...Lel\n }\n }\n': typeof types.BarDocument; }; const documents: Documents = { '\n query Foo {\n Tweets {\n id\n }\n }\n': types.FooDocument, - '\n fragment Lel on Tweet {\n id\n body\n }\n': types.LelFragmentDoc, + '\n fragment Lel on Tweet {\n id\n body\n date\n }\n': types.LelFragmentDoc, '\n query Bar {\n Tweets {\n ...Lel\n }\n }\n': types.BarDocument, }; @@ -48,8 +48,8 @@ export function graphql( * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( - source: '\n fragment Lel on Tweet {\n id\n body\n }\n' -): (typeof documents)['\n fragment Lel on Tweet {\n id\n body\n }\n']; + source: '\n fragment Lel on Tweet {\n id\n body\n date\n }\n' +): (typeof documents)['\n fragment Lel on Tweet {\n id\n body\n date\n }\n']; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/dev-test/gql-tag-operations/gql/graphql.ts b/dev-test/gql-tag-operations/gql/graphql.ts index addcd45db1c..4ea5fb35e38 100644 --- a/dev-test/gql-tag-operations/gql/graphql.ts +++ b/dev-test/gql-tag-operations/gql/graphql.ts @@ -6,7 +6,9 @@ export type FooQueryVariables = Exact<{ [key: string]: never }>; export type FooQuery = { Tweets: Array<{ id: string } | null> | null }; -export type LelFragment = { id: string; body: string | null } & { ' $fragmentName'?: 'LelFragment' }; +export type LelFragment = { id: string; body: string | null; date: unknown | null } & { + ' $fragmentName'?: 'LelFragment'; +}; export type BarQueryVariables = Exact<{ [key: string]: never }>; @@ -24,6 +26,7 @@ export const LelFragmentDoc = { selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'body' } }, + { kind: 'Field', name: { kind: 'Name', value: 'date' } }, ], }, }, @@ -82,6 +85,7 @@ export const BarDocument = { selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'body' } }, + { kind: 'Field', name: { kind: 'Name', value: 'date' } }, ], }, }, diff --git a/dev-test/gql-tag-operations/graphql/gql.ts b/dev-test/gql-tag-operations/graphql/gql.ts index 0c2e0dfeb12..966c8b09699 100644 --- a/dev-test/gql-tag-operations/graphql/gql.ts +++ b/dev-test/gql-tag-operations/graphql/gql.ts @@ -15,12 +15,12 @@ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/ */ type Documents = { '\n query Foo {\n Tweets {\n id\n }\n }\n': typeof types.FooDocument; - '\n fragment Lel on Tweet {\n id\n body\n }\n': typeof types.LelFragmentDoc; + '\n fragment Lel on Tweet {\n id\n body\n date\n }\n': typeof types.LelFragmentDoc; '\n query Bar {\n Tweets {\n ...Lel\n }\n }\n': typeof types.BarDocument; }; const documents: Documents = { '\n query Foo {\n Tweets {\n id\n }\n }\n': types.FooDocument, - '\n fragment Lel on Tweet {\n id\n body\n }\n': types.LelFragmentDoc, + '\n fragment Lel on Tweet {\n id\n body\n date\n }\n': types.LelFragmentDoc, '\n query Bar {\n Tweets {\n ...Lel\n }\n }\n': types.BarDocument, }; @@ -48,8 +48,8 @@ export function graphql( * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( - source: '\n fragment Lel on Tweet {\n id\n body\n }\n' -): (typeof documents)['\n fragment Lel on Tweet {\n id\n body\n }\n']; + source: '\n fragment Lel on Tweet {\n id\n body\n date\n }\n' +): (typeof documents)['\n fragment Lel on Tweet {\n id\n body\n date\n }\n']; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/dev-test/gql-tag-operations/graphql/graphql.ts b/dev-test/gql-tag-operations/graphql/graphql.ts index addcd45db1c..4ea5fb35e38 100644 --- a/dev-test/gql-tag-operations/graphql/graphql.ts +++ b/dev-test/gql-tag-operations/graphql/graphql.ts @@ -6,7 +6,9 @@ export type FooQueryVariables = Exact<{ [key: string]: never }>; export type FooQuery = { Tweets: Array<{ id: string } | null> | null }; -export type LelFragment = { id: string; body: string | null } & { ' $fragmentName'?: 'LelFragment' }; +export type LelFragment = { id: string; body: string | null; date: unknown | null } & { + ' $fragmentName'?: 'LelFragment'; +}; export type BarQueryVariables = Exact<{ [key: string]: never }>; @@ -24,6 +26,7 @@ export const LelFragmentDoc = { selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'body' } }, + { kind: 'Field', name: { kind: 'Name', value: 'date' } }, ], }, }, @@ -82,6 +85,7 @@ export const BarDocument = { selections: [ { kind: 'Field', name: { kind: 'Name', value: 'id' } }, { kind: 'Field', name: { kind: 'Name', value: 'body' } }, + { kind: 'Field', name: { kind: 'Name', value: 'date' } }, ], }, }, diff --git a/dev-test/gql-tag-operations/src/index.ts b/dev-test/gql-tag-operations/src/index.ts index e491e7984a2..673be52a6d8 100644 --- a/dev-test/gql-tag-operations/src/index.ts +++ b/dev-test/gql-tag-operations/src/index.ts @@ -14,6 +14,7 @@ const LelFragment = graphql(/* GraphQL */ ` fragment Lel on Tweet { id body + date } `); diff --git a/dev-test/test-schema/resolvers-federation.ts b/dev-test/test-schema/resolvers-federation.ts index 24ee77f9b14..19a2a55762d 100644 --- a/dev-test/test-schema/resolvers-federation.ts +++ b/dev-test/test-schema/resolvers-federation.ts @@ -8,7 +8,7 @@ export type Scalars = { Boolean: { input: boolean; output: boolean }; Int: { input: number; output: number }; Float: { input: number; output: number }; - _FieldSet: { input: any; output: any }; + _FieldSet: { input: unknown; output: unknown }; }; export type Address = { diff --git a/packages/graphql-codegen-cli/tests/codegen.spec.ts b/packages/graphql-codegen-cli/tests/codegen.spec.ts index 4d447a47178..f56f5a19291 100644 --- a/packages/graphql-codegen-cli/tests/codegen.spec.ts +++ b/packages/graphql-codegen-cli/tests/codegen.spec.ts @@ -695,7 +695,7 @@ describe('Codegen Executor', () => { Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } - UniqueID: { input: any; output: any; } + UniqueID: { input: unknown; output: unknown; } };`); }); }); diff --git a/packages/plugins/other/visitor-plugin-common/src/base-visitor.ts b/packages/plugins/other/visitor-plugin-common/src/base-visitor.ts index f029cac6fb6..3eeb6b85f11 100644 --- a/packages/plugins/other/visitor-plugin-common/src/base-visitor.ts +++ b/packages/plugins/other/visitor-plugin-common/src/base-visitor.ts @@ -70,7 +70,7 @@ export interface RawConfig { strictScalars?: boolean; /** * @description Allows you to override the type that unknown scalars will have. - * @default any + * @default unknown * * @exampleMarkdown * ```ts filename="codegen.ts" @@ -82,7 +82,7 @@ export interface RawConfig { * 'path/to/file': { * // plugins... * config: { - * defaultScalarType: 'unknown' + * defaultScalarType: 'any' * }, * }, * }, diff --git a/packages/plugins/other/visitor-plugin-common/src/utils.ts b/packages/plugins/other/visitor-plugin-common/src/utils.ts index ce4effb4268..fd76f75e850 100644 --- a/packages/plugins/other/visitor-plugin-common/src/utils.ts +++ b/packages/plugins/other/visitor-plugin-common/src/utils.ts @@ -269,7 +269,7 @@ export function buildScalarsFromConfig( schema: GraphQLSchema | undefined, config: RawConfig, defaultScalarsMapping: NormalizedScalarsMap = DEFAULT_SCALARS, - defaultScalarType = 'any' + defaultScalarType = 'unknown' ): ParsedScalarsMap { return buildScalars( schema, @@ -283,7 +283,7 @@ export function buildScalars( schema: GraphQLSchema | undefined, scalarsMapping: ScalarsMap, defaultScalarsMapping: NormalizedScalarsMap = DEFAULT_SCALARS, - defaultScalarType: string | null = 'any' + defaultScalarType: string | null = 'unknown' ): ParsedScalarsMap { const result: ParsedScalarsMap = {}; diff --git a/packages/plugins/typescript/operations/src/ts-operation-variables-to-object.ts b/packages/plugins/typescript/operations/src/ts-operation-variables-to-object.ts index b8ea3e147cd..105240bed96 100644 --- a/packages/plugins/typescript/operations/src/ts-operation-variables-to-object.ts +++ b/packages/plugins/typescript/operations/src/ts-operation-variables-to-object.ts @@ -28,6 +28,6 @@ export class TypeScriptOperationVariablesToObject extends TSOperationVariablesTo } protected getScalar(name: string): string { - return this._scalars?.[name]?.input ?? SCALARS[name] ?? 'any'; + return this._scalars?.[name]?.input ?? SCALARS[name] ?? 'unknown'; } } diff --git a/packages/plugins/typescript/operations/src/visitor.ts b/packages/plugins/typescript/operations/src/visitor.ts index 1089c669ba5..5736bd5dc15 100644 --- a/packages/plugins/typescript/operations/src/visitor.ts +++ b/packages/plugins/typescript/operations/src/visitor.ts @@ -100,6 +100,7 @@ export class TypeScriptDocumentsVisitor extends BaseDocumentsVisitor< }), ignoreEnumValuesFromSchema: getConfigValue(config.ignoreEnumValuesFromSchema, false), futureProofEnums: getConfigValue(config.futureProofEnums, false), + maybeValue: getConfigValue(config.maybeValue, 'T | null'), } as TypeScriptDocumentsParsedConfig, schema ); @@ -107,9 +108,6 @@ export class TypeScriptDocumentsVisitor extends BaseDocumentsVisitor< this._outputPath = outputPath; autoBind(this); - const defaultMaybeValue = 'T | null'; - const maybeValue = getConfigValue(config.maybeValue, defaultMaybeValue); - const allFragments: LoadedFragment[] = [ ...(documentNode.definitions.filter(d => d.kind === Kind.FRAGMENT_DEFINITION) as FragmentDefinitionNode[]).map( fragmentDef => ({ @@ -135,7 +133,7 @@ export class TypeScriptDocumentsVisitor extends BaseDocumentsVisitor< }, wrapTypeWithModifiers: (baseType, type) => { return wrapTypeWithModifiers(baseType, type, { - wrapOptional: type => maybeValue.replace('T', type), + wrapOptional: type => this.config.maybeValue.replace('T', type), wrapArray: type => { const listModifier = this.config.immutableTypes ? 'ReadonlyArray' : 'Array'; return `${listModifier}<${type}>`; @@ -270,7 +268,7 @@ export class TypeScriptDocumentsVisitor extends BaseDocumentsVisitor< } typePart = usedInputType.tsType; // If the schema is correct, when reversing typeNodes, the first node would be `NamedType`, which means we can safely set it as the base for typePart - if (usedInputType.tsType !== 'any' && !typeNode.isNonNullable) { + if (!typeNode.isNonNullable) { typePart += ' | null | undefined'; } continue; @@ -409,7 +407,7 @@ export class TypeScriptDocumentsVisitor extends BaseDocumentsVisitor< usedInputTypes[node.name] = { type: 'GraphQLScalarType', node, - tsType: (SCALARS[node.name] || this.config.scalars?.[node.name]?.input.type) ?? 'any', + tsType: (SCALARS[node.name] || this.config.scalars?.[node.name]?.input.type) ?? 'unknown', }; return; } diff --git a/packages/plugins/typescript/operations/tests/__snapshots__/ts-documents.spec.ts.snap b/packages/plugins/typescript/operations/tests/__snapshots__/ts-documents.spec.ts.snap index 760b49909be..e77992ab326 100644 --- a/packages/plugins/typescript/operations/tests/__snapshots__/ts-documents.spec.ts.snap +++ b/packages/plugins/typescript/operations/tests/__snapshots__/ts-documents.spec.ts.snap @@ -18,10 +18,10 @@ exports[`TypeScript Operations Plugin > Issues > #2699 - Issues with multiple in export type GetEntityBrandDataQuery = { node: - | { __typename: 'Company', active: boolean, id: string, createdAt: any, updatedAt: any, brandData: { active: boolean, browsable: boolean, title: string, alternateTitle: string | null, description: string } | null, createdBy: { id: string, name: string } | null, updatedBy: { id: string, name: string } | null } - | { __typename: 'Theater', active: boolean, id: string, createdAt: any, updatedAt: any, brandData: { active: boolean, browsable: boolean, title: string, alternateTitle: string | null, description: string } | null, createdBy: { id: string, name: string } | null, updatedBy: { id: string, name: string } | null } - | { __typename: 'Movie', id: string, createdAt: any, updatedAt: any, brandData: { active: boolean, browsable: boolean, title: string, alternateTitle: string | null, description: string } | null, createdBy: { id: string, name: string } | null, updatedBy: { id: string, name: string } | null } - | { __typename: 'User', id: string, createdAt: any, updatedAt: any, brandData: { active: boolean, browsable: boolean, title: string, alternateTitle: string | null, description: string } | null, createdBy: { id: string, name: string } | null, updatedBy: { id: string, name: string } | null } + | { __typename: 'Company', active: boolean, id: string, createdAt: unknown, updatedAt: unknown, brandData: { active: boolean, browsable: boolean, title: string, alternateTitle: string | null, description: string } | null, createdBy: { id: string, name: string } | null, updatedBy: { id: string, name: string } | null } + | { __typename: 'Theater', active: boolean, id: string, createdAt: unknown, updatedAt: unknown, brandData: { active: boolean, browsable: boolean, title: string, alternateTitle: string | null, description: string } | null, createdBy: { id: string, name: string } | null, updatedBy: { id: string, name: string } | null } + | { __typename: 'Movie', id: string, createdAt: unknown, updatedAt: unknown, brandData: { active: boolean, browsable: boolean, title: string, alternateTitle: string | null, description: string } | null, createdBy: { id: string, name: string } | null, updatedBy: { id: string, name: string } | null } + | { __typename: 'User', id: string, createdAt: unknown, updatedAt: unknown, brandData: { active: boolean, browsable: boolean, title: string, alternateTitle: string | null, description: string } | null, createdBy: { id: string, name: string } | null, updatedBy: { id: string, name: string } | null } }; type EntityBrandData_Company_Fragment = { brandData: { active: boolean, browsable: boolean, title: string, alternateTitle: string | null, description: string } | null }; @@ -39,13 +39,13 @@ export type EntityBrandDataFragment = | EntityBrandData_User_Fragment ; -type ElementMetadata_Company_Fragment = { createdAt: any, updatedAt: any, createdBy: { id: string, name: string } | null, updatedBy: { id: string, name: string } | null }; +type ElementMetadata_Company_Fragment = { createdAt: unknown, updatedAt: unknown, createdBy: { id: string, name: string } | null, updatedBy: { id: string, name: string } | null }; -type ElementMetadata_Theater_Fragment = { createdAt: any, updatedAt: any, createdBy: { id: string, name: string } | null, updatedBy: { id: string, name: string } | null }; +type ElementMetadata_Theater_Fragment = { createdAt: unknown, updatedAt: unknown, createdBy: { id: string, name: string } | null, updatedBy: { id: string, name: string } | null }; -type ElementMetadata_Movie_Fragment = { createdAt: any, updatedAt: any, createdBy: { id: string, name: string } | null, updatedBy: { id: string, name: string } | null }; +type ElementMetadata_Movie_Fragment = { createdAt: unknown, updatedAt: unknown, createdBy: { id: string, name: string } | null, updatedBy: { id: string, name: string } | null }; -type ElementMetadata_User_Fragment = { createdAt: any, updatedAt: any, createdBy: { id: string, name: string } | null, updatedBy: { id: string, name: string } | null }; +type ElementMetadata_User_Fragment = { createdAt: unknown, updatedAt: unknown, createdBy: { id: string, name: string } | null, updatedBy: { id: string, name: string } | null }; export type ElementMetadataFragment = | ElementMetadata_Company_Fragment @@ -155,9 +155,9 @@ export type AaaQuery = { user: `; exports[`TypeScript Operations Plugin > Selection Set > Should have valid __typename usage and split types according to that (with usage) 1`] = ` -"type NetRoute_Ipv4Route_Fragment = { __typename: 'IPV4Route', ipv4Address: any | null, ipv4Gateway: any | null }; +"type NetRoute_Ipv4Route_Fragment = { __typename: 'IPV4Route', ipv4Address: unknown | null, ipv4Gateway: unknown | null }; -type NetRoute_Ipv6Route_Fragment = { __typename: 'IPV6Route', ipv6Address: any | null, ipv6Gateway: any | null }; +type NetRoute_Ipv6Route_Fragment = { __typename: 'IPV6Route', ipv6Address: unknown | null, ipv6Gateway: unknown | null }; export type NetRouteFragment = | NetRoute_Ipv4Route_Fragment @@ -168,30 +168,30 @@ export type QqQueryVariables = Exact<{ [key: string]: never; }>; export type QqQuery = { routes: Array< - | { __typename: 'IPV4Route', ipv4Address: any | null, ipv4Gateway: any | null } - | { __typename: 'IPV6Route', ipv6Address: any | null, ipv6Gateway: any | null } + | { __typename: 'IPV4Route', ipv4Address: unknown | null, ipv4Gateway: unknown | null } + | { __typename: 'IPV6Route', ipv6Address: unknown | null, ipv6Gateway: unknown | null } > }; " `; exports[`TypeScript Operations Plugin > Selection Set > Should have valid __typename usage and split types according to that (with usage) 2`] = ` -"type NetRoute_Ipv4Route_Fragment = { __typename: 'IPV4Route', ipv4Address: any | null, ipv4Gateway: any | null }; +"type NetRoute_Ipv4Route_Fragment = { __typename: 'IPV4Route', ipv4Address: unknown | null, ipv4Gateway: unknown | null }; -type NetRoute_Ipv6Route_Fragment = { __typename: 'IPV6Route', ipv6Address: any | null, ipv6Gateway: any | null }; +type NetRoute_Ipv6Route_Fragment = { __typename: 'IPV6Route', ipv6Address: unknown | null, ipv6Gateway: unknown | null }; export type NetRouteFragment = | NetRoute_Ipv4Route_Fragment | NetRoute_Ipv6Route_Fragment ; -export type TestFragment = { ipv6Address: any | null, ipv6Gateway: any | null }; +export type TestFragment = { ipv6Address: unknown | null, ipv6Gateway: unknown | null }; export type QqQueryVariables = Exact<{ [key: string]: never; }>; export type QqQuery = { routes: Array< - | { __typename: 'IPV4Route', ipv4Address: any | null, ipv4Gateway: any | null } - | { __typename: 'IPV6Route', ipv6Address: any | null, ipv6Gateway: any | null } + | { __typename: 'IPV4Route', ipv4Address: unknown | null, ipv4Gateway: unknown | null } + | { __typename: 'IPV6Route', ipv6Address: unknown | null, ipv6Gateway: unknown | null } > }; " `; diff --git a/packages/plugins/typescript/operations/tests/extract-all-types.spec.ts b/packages/plugins/typescript/operations/tests/extract-all-types.spec.ts index e371099abe9..31279e63ce7 100644 --- a/packages/plugins/typescript/operations/tests/extract-all-types.spec.ts +++ b/packages/plugins/typescript/operations/tests/extract-all-types.spec.ts @@ -84,13 +84,13 @@ describe('extractAllFieldsToTypes: true', () => { "type UserFragment_DummyUser = { __typename: 'DummyUser', id: string, - joinDate: any + joinDate: unknown }; type UserFragment_ActiveUser = { __typename: 'ActiveUser', id: string, - joinDate: any + joinDate: unknown }; export type UserFragment = @@ -101,13 +101,13 @@ describe('extractAllFieldsToTypes: true', () => { export type MeFragment_ActiveUser_parentUser_DummyUser = { __typename: 'DummyUser', id: string, - joinDate: any + joinDate: unknown }; export type MeFragment_ActiveUser_parentUser_ActiveUser = { __typename: 'ActiveUser', id: string, - joinDate: any + joinDate: unknown }; export type MeFragment_ActiveUser_parentUser = @@ -118,14 +118,14 @@ describe('extractAllFieldsToTypes: true', () => { type Me_DummyUser_Fragment = { __typename: 'DummyUser', id: string, - joinDate: any + joinDate: unknown }; type Me_ActiveUser_Fragment = { __typename: 'ActiveUser', isActive: boolean, id: string, - joinDate: any, + joinDate: unknown, parentUser: MeFragment_ActiveUser_parentUser }; @@ -137,14 +137,14 @@ describe('extractAllFieldsToTypes: true', () => { export type OverlappingFieldsMergingTestQuery_me_DummyUser = { __typename: 'DummyUser', id: string, - joinDate: any + joinDate: unknown }; export type OverlappingFieldsMergingTestQuery_me_ActiveUser = { __typename: 'ActiveUser', id: string, isActive: boolean, - joinDate: any, + joinDate: unknown, parentUser: MeFragment_ActiveUser_parentUser }; @@ -167,14 +167,14 @@ describe('extractAllFieldsToTypes: true', () => { export type NestedOverlappingFieldsMergingTestQuery_me_DummyUser = { __typename: 'DummyUser', id: string, - joinDate: any + joinDate: unknown }; export type NestedOverlappingFieldsMergingTestQuery_me_ActiveUser = { __typename: 'ActiveUser', isActive: boolean, id: string, - joinDate: any, + joinDate: unknown, parentUser: MeFragment_ActiveUser_parentUser }; diff --git a/packages/plugins/typescript/operations/tests/ts-documents.spec.ts b/packages/plugins/typescript/operations/tests/ts-documents.spec.ts index 30c7261d463..6849898aae5 100644 --- a/packages/plugins/typescript/operations/tests/ts-documents.spec.ts +++ b/packages/plugins/typescript/operations/tests/ts-documents.spec.ts @@ -2749,7 +2749,7 @@ export type Q2Query = { search: Array< expect(content).toMatchInlineSnapshot( ` "export type TestQueryQueryVariables = Exact<{ - test?: any | null; + test?: unknown | null; }>; diff --git a/packages/plugins/typescript/operations/tests/ts-documents.standalone.default-scalar-types.spec.ts b/packages/plugins/typescript/operations/tests/ts-documents.standalone.default-scalar-types.spec.ts new file mode 100644 index 00000000000..bb55e79e7ea --- /dev/null +++ b/packages/plugins/typescript/operations/tests/ts-documents.standalone.default-scalar-types.spec.ts @@ -0,0 +1,283 @@ +import { mergeOutputs } from '@graphql-codegen/plugin-helpers'; +import { validateTs } from '@graphql-codegen/testing'; +import { buildSchema, parse } from 'graphql'; +import { plugin } from '../src/index.js'; + +describe('TypeScript Operations Plugin - Default Scalar types', () => { + it('generates `unknown` as the default custom defaultScalarType', async () => { + const schema = buildSchema(/* GraphQL */ ` + type Query { + user( + id: ID! + nonNullableDate: DateTime! + nullableDate: DateTime + dateArray1: [DateTime] + dateArray2: [DateTime]! + dateArray3: [DateTime!] + dateArray4: [DateTime!]! + input: UserInput! + ): User + } + + input UserInput { + nonNullableDate: DateTime! + nullableDate: DateTime + dateArray1: [DateTime] + dateArray2: [DateTime]! + dateArray3: [DateTime!] + dateArray4: [DateTime!]! + } + + type User { + id: ID! + nonNullableDate: DateTime! + nullableDate: DateTime + } + + scalar DateTime + `); + const document = parse(/* GraphQL */ ` + query User( + $nonNullableDate: DateTime! + $nullableDate: DateTime + $dateArray1: [DateTime] + $dateArray2: [DateTime]! + $dateArray3: [DateTime!] + $dateArray4: [DateTime!]! + $input: UserInput! + ) { + user( + id: "1" + nonNullableDate: $nonNullableDate + nullableDate: $nullableDate + dateArray1: $dateArray1 + dateArray2: $dateArray2 + dateArray3: $dateArray3 + dateArray4: $dateArray4 + input: $input + ) { + id + nonNullableDate + nullableDate + } + } + `); + + const result = mergeOutputs([await plugin(schema, [{ document }], {}, { outputFile: '' })]); + + expect(result).toMatchInlineSnapshot(` + "type Exact = { [K in keyof T]: T[K] }; + export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; + type UserInput = { + nonNullableDate: unknown; + nullableDate?: unknown | null | undefined; + dateArray1?: Array | null | undefined; + dateArray2: Array; + dateArray3?: Array | null | undefined; + dateArray4: Array; + }; + + export type UserQueryVariables = Exact<{ + nonNullableDate: unknown; + nullableDate?: unknown | null; + dateArray1?: Array | unknown | null; + dateArray2: Array | unknown; + dateArray3?: Array | unknown | null; + dateArray4: Array | unknown; + input: UserInput; + }>; + + + export type UserQuery = { user: { id: string, nonNullableDate: unknown, nullableDate: unknown | null } | null }; + " + `); + + validateTs(result, undefined, undefined, undefined, undefined, true); + }); + + it("generates `any` when defaultScalarType:'any'", async () => { + const schema = buildSchema(/* GraphQL */ ` + type Query { + user( + id: ID! + nonNullableDate: DateTime! + nullableDate: DateTime + dateArray1: [DateTime] + dateArray2: [DateTime]! + dateArray3: [DateTime!] + dateArray4: [DateTime!]! + input: UserInput! + ): User + } + + input UserInput { + nonNullableDate: DateTime! + nullableDate: DateTime + dateArray1: [DateTime] + dateArray2: [DateTime]! + dateArray3: [DateTime!] + dateArray4: [DateTime!]! + } + + type User { + id: ID! + nonNullableDate: DateTime! + nullableDate: DateTime + } + + scalar DateTime + `); + const document = parse(/* GraphQL */ ` + query User( + $nonNullableDate: DateTime! + $nullableDate: DateTime + $dateArray1: [DateTime] + $dateArray2: [DateTime]! + $dateArray3: [DateTime!] + $dateArray4: [DateTime!]! + $input: UserInput! + ) { + user( + id: "1" + nonNullableDate: $nonNullableDate + nullableDate: $nullableDate + dateArray1: $dateArray1 + dateArray2: $dateArray2 + dateArray3: $dateArray3 + dateArray4: $dateArray4 + input: $input + ) { + id + nonNullableDate + nullableDate + } + } + `); + + const result = mergeOutputs([ + await plugin(schema, [{ document }], { defaultScalarType: 'any' }, { outputFile: '' }), + ]); + + expect(result).toMatchInlineSnapshot(` + "type Exact = { [K in keyof T]: T[K] }; + export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; + type UserInput = { + nonNullableDate: any; + nullableDate?: any | null | undefined; + dateArray1?: Array | null | undefined; + dateArray2: Array; + dateArray3?: Array | null | undefined; + dateArray4: Array; + }; + + export type UserQueryVariables = Exact<{ + nonNullableDate: any; + nullableDate?: any | null; + dateArray1?: Array | any | null; + dateArray2: Array | any; + dateArray3?: Array | any | null; + dateArray4: Array | any; + input: UserInput; + }>; + + + export type UserQuery = { user: { id: string, nonNullableDate: any, nullableDate: any | null } | null }; + " + `); + + validateTs(result, undefined, undefined, undefined, undefined, true); + }); + + it('generates correct types when defaultScalarType is set to said types', async () => { + const schema = buildSchema(/* GraphQL */ ` + type Query { + user( + id: ID! + nonNullableDate: DateTime! + nullableDate: DateTime + dateArray1: [DateTime] + dateArray2: [DateTime]! + dateArray3: [DateTime!] + dateArray4: [DateTime!]! + input: UserInput! + ): User + } + + input UserInput { + nonNullableDate: DateTime! + nullableDate: DateTime + dateArray1: [DateTime] + dateArray2: [DateTime]! + dateArray3: [DateTime!] + dateArray4: [DateTime!]! + } + + type User { + id: ID! + nonNullableDate: DateTime! + nullableDate: DateTime + } + + scalar DateTime + `); + const document = parse(/* GraphQL */ ` + query User( + $nonNullableDate: DateTime! + $nullableDate: DateTime + $dateArray1: [DateTime] + $dateArray2: [DateTime]! + $dateArray3: [DateTime!] + $dateArray4: [DateTime!]! + $input: UserInput! + ) { + user( + id: "1" + nonNullableDate: $nonNullableDate + nullableDate: $nullableDate + dateArray1: $dateArray1 + dateArray2: $dateArray2 + dateArray3: $dateArray3 + dateArray4: $dateArray4 + input: $input + ) { + id + nonNullableDate + nullableDate + } + } + `); + + const result = mergeOutputs([ + await plugin(schema, [{ document }], { defaultScalarType: 'Date' }, { outputFile: '' }), + ]); + + expect(result).toMatchInlineSnapshot(` + "type Exact = { [K in keyof T]: T[K] }; + export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; + type UserInput = { + nonNullableDate: Date; + nullableDate?: Date | null | undefined; + dateArray1?: Array | null | undefined; + dateArray2: Array; + dateArray3?: Array | null | undefined; + dateArray4: Array; + }; + + export type UserQueryVariables = Exact<{ + nonNullableDate: Date; + nullableDate?: Date | null; + dateArray1?: Array | Date | null; + dateArray2: Array | Date; + dateArray3?: Array | Date | null; + dateArray4: Array | Date; + input: UserInput; + }>; + + + export type UserQuery = { user: { id: string, nonNullableDate: Date, nullableDate: Date | null } | null }; + " + `); + + validateTs(result, undefined, undefined, undefined, undefined, true); + }); +}); diff --git a/packages/plugins/typescript/operations/tests/ts-documents.standalone.import-types.spec.ts b/packages/plugins/typescript/operations/tests/ts-documents.standalone.import-types.spec.ts index 782fc23d9ec..fd7f2687d21 100644 --- a/packages/plugins/typescript/operations/tests/ts-documents.standalone.import-types.spec.ts +++ b/packages/plugins/typescript/operations/tests/ts-documents.standalone.import-types.spec.ts @@ -110,9 +110,9 @@ describe('TypeScript Operations Plugin - Import Types', () => { /** UsersInput Description */ type UsersInput = { /** UsersInput from */ - from?: any; + from?: unknown | null | undefined; /** UsersInput to */ - to?: any; + to?: unknown | null | undefined; role?: UserRole | null | undefined; }; @@ -121,7 +121,7 @@ describe('TypeScript Operations Plugin - Import Types', () => { }>; - export type UserQuery = { user: { id: string, name: string, role: TypeImport.UserRole, createdAt: any } | null }; + export type UserQuery = { user: { id: string, name: string, role: TypeImport.UserRole, createdAt: unknown } | null }; export type UsersQueryVariables = Exact<{ input: TypeImport.UsersInput; @@ -134,8 +134,8 @@ describe('TypeScript Operations Plugin - Import Types', () => { }; export type UsersWithScalarInputQueryVariables = Exact<{ - from: any; - to?: any | null; + from: unknown; + to?: unknown | null; role?: TypeImport.UserRole | null; }>; @@ -254,9 +254,9 @@ describe('TypeScript Operations Plugin - Import Types', () => { /** UsersInput Description */ type UsersInput = { /** UsersInput from */ - from?: any; + from?: unknown | null | undefined; /** UsersInput to */ - to?: any; + to?: unknown | null | undefined; role?: UserRole | null | undefined; }; @@ -265,7 +265,7 @@ describe('TypeScript Operations Plugin - Import Types', () => { }>; - export type UserQuery = { user: { id: string, name: string, role: TypeImport.UserRole, createdAt: any } | null }; + export type UserQuery = { user: { id: string, name: string, role: TypeImport.UserRole, createdAt: unknown } | null }; export type UsersQueryVariables = Exact<{ input: TypeImport.UsersInput; @@ -278,8 +278,8 @@ describe('TypeScript Operations Plugin - Import Types', () => { }; export type UsersWithScalarInputQueryVariables = Exact<{ - from: any; - to?: any | null; + from: unknown; + to?: unknown | null; role?: TypeImport.UserRole | null; }>; diff --git a/packages/plugins/typescript/operations/tests/ts-documents.standalone.input.spec.ts b/packages/plugins/typescript/operations/tests/ts-documents.standalone.input.spec.ts index 03d33e1d2ec..3dc3b25f127 100644 --- a/packages/plugins/typescript/operations/tests/ts-documents.standalone.input.spec.ts +++ b/packages/plugins/typescript/operations/tests/ts-documents.standalone.input.spec.ts @@ -7,7 +7,7 @@ describe('TypeScript Operations Plugin - Input', () => { it('generates nested input correctly', async () => { const schema = buildSchema(/* GraphQL */ ` type Query { - users(input: UsersInput!): [User!]! + users(input: UsersInput!, ageRange1: [Int], ageRange2: [Int]!, ageRange3: [Int!], ageRange4: [Int!]!): [User!]! } type ResponseError { @@ -61,8 +61,21 @@ describe('TypeScript Operations Plugin - Input', () => { scalar TimeZone `); const document = parse(/* GraphQL */ ` - query UsersWithScalarInput($inputNonNullable: UsersInput!, $inputNullable: UsersInput) { - users(input: $inputNonNullable) { + query UsersWithScalarInput( + $inputNonNullable: UsersInput! + $inputNullable: UsersInput + $ageRange1: [Int] + $ageRange2: [Int]! + $ageRange3: [Int!] + $ageRange4: [Int!]! + ) { + users( + input: $inputNonNullable + ageRange1: $ageRange1 + ageRange2: $ageRange2 + ageRange3: $ageRange3 + ageRange4: $ageRange4 + ) { ageRange1 ageRange2 ageRange3 @@ -100,7 +113,7 @@ describe('TypeScript Operations Plugin - Input', () => { from?: Date | null | undefined; /** UsersInput to */ to?: Date | null | undefined; - timezone?: any; + timezone?: unknown | null | undefined; role?: UserRole | null | undefined; ageRange1?: Array | null | undefined; ageRange2: Array; @@ -117,6 +130,10 @@ describe('TypeScript Operations Plugin - Input', () => { export type UsersWithScalarInputQueryVariables = Exact<{ inputNonNullable: UsersInput; inputNullable?: UsersInput | null; + ageRange1?: Array | number | null; + ageRange2: Array | number; + ageRange3?: Array | number | null; + ageRange4: Array | number; }>; @@ -224,7 +241,7 @@ describe('TypeScript Operations Plugin - Input', () => { readonly from?: Date | null | undefined; /** UsersInput to */ readonly to?: Date | null | undefined; - readonly timezone?: any; + readonly timezone?: unknown | null | undefined; readonly role?: UserRole | null | undefined; readonly ageRange1?: Array | null | undefined; readonly ageRange2: Array; @@ -344,7 +361,7 @@ describe('TypeScript Operations Plugin - Input', () => { from: Date; to?: never; timezone?: never; role?: never; ageRange1?: never; ageRange3?: never; bestFriend?: never; nestedInput?: never; } | { from?: never; /** UsersInput to */ to: Date; timezone?: never; role?: never; ageRange1?: never; ageRange3?: never; bestFriend?: never; nestedInput?: never; } - | { from?: never; to?: never; timezone: any; role?: never; ageRange1?: never; ageRange3?: never; bestFriend?: never; nestedInput?: never; } + | { from?: never; to?: never; timezone: unknown; role?: never; ageRange1?: never; ageRange3?: never; bestFriend?: never; nestedInput?: never; } | { from?: never; to?: never; timezone?: never; role: UserRole; ageRange1?: never; ageRange3?: never; bestFriend?: never; nestedInput?: never; } | { from?: never; to?: never; timezone?: never; role?: never; ageRange1: Array; ageRange3?: never; bestFriend?: never; nestedInput?: never; } | { from?: never; to?: never; timezone?: never; role?: never; ageRange1?: never; ageRange3: Array; bestFriend?: never; nestedInput?: never; } diff --git a/packages/plugins/typescript/operations/tests/ts-documents.standalone.spec.ts b/packages/plugins/typescript/operations/tests/ts-documents.standalone.spec.ts index 91ed3b431c4..a4ce0116403 100644 --- a/packages/plugins/typescript/operations/tests/ts-documents.standalone.spec.ts +++ b/packages/plugins/typescript/operations/tests/ts-documents.standalone.spec.ts @@ -138,9 +138,9 @@ describe('TypeScript Operations Plugin - Standalone', () => { /** UsersInput Description */ type UsersInput = { /** UsersInput from */ - from?: any; + from?: unknown | null | undefined; /** UsersInput to */ - to?: any; + to?: unknown | null | undefined; role?: UserRole | null | undefined; }; @@ -149,7 +149,7 @@ describe('TypeScript Operations Plugin - Standalone', () => { }>; - export type UserQuery = { user: { id: string, name: string, role: UserRole, createdAt: any, nickname: string | null } | null }; + export type UserQuery = { user: { id: string, name: string, role: UserRole, createdAt: unknown, nickname: string | null } | null }; export type UsersQueryVariables = Exact<{ input: UsersInput; @@ -162,8 +162,8 @@ describe('TypeScript Operations Plugin - Standalone', () => { }; export type UsersWithScalarInputQueryVariables = Exact<{ - from: any; - to?: any | null; + from: unknown; + to?: unknown | null; role?: UserRole | null; }>; @@ -654,9 +654,9 @@ describe('TypeScript Operations Plugin - Standalone', () => { /** UsersInput Description */ type UsersInput = { /** UsersInput from */ - from?: any; + from?: unknown | null | undefined; /** UsersInput to */ - to?: any; + to?: unknown | null | undefined; role?: UserRole | null | undefined; }; " @@ -802,7 +802,7 @@ describe('TypeScript Operations Plugin - Standalone', () => { }>; - export type UserQuery = { user: { __typename: 'User', id: string, name: string, createdAt: any, bestFriend: { __typename: 'User', name: string } | null, goodFriends: Array<{ __typename: 'User', id: string }> } | null }; + export type UserQuery = { user: { __typename: 'User', id: string, name: string, createdAt: unknown, bestFriend: { __typename: 'User', name: string } | null, goodFriends: Array<{ __typename: 'User', id: string }> } | null }; " `); diff --git a/packages/plugins/typescript/resolvers/tests/__snapshots__/ts-resolvers.spec.ts.snap b/packages/plugins/typescript/resolvers/tests/__snapshots__/ts-resolvers.spec.ts.snap index 5b2d327f9c2..3960c3ecb53 100644 --- a/packages/plugins/typescript/resolvers/tests/__snapshots__/ts-resolvers.spec.ts.snap +++ b/packages/plugins/typescript/resolvers/tests/__snapshots__/ts-resolvers.spec.ts.snap @@ -13,7 +13,7 @@ export type Scalars = { Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } - MyScalar: { input: any; output: any; } + MyScalar: { input: unknown; output: unknown; } }; export type MyType = { @@ -628,7 +628,7 @@ export type Scalars = { Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } - MyScalar: { input: any; output: any; } + MyScalar: { input: unknown; output: unknown; } }; export type MyType = { diff --git a/packages/plugins/typescript/typescript/tests/typescript.spec.ts b/packages/plugins/typescript/typescript/tests/typescript.spec.ts index f829c5e2550..967daa46a07 100644 --- a/packages/plugins/typescript/typescript/tests/typescript.spec.ts +++ b/packages/plugins/typescript/typescript/tests/typescript.spec.ts @@ -29,7 +29,7 @@ describe('TypeScript', () => { Int: { input: number; output: number; } Float: { input: number; output: number; } /** My custom scalar */ - A: { input: any; output: any; } + A: { input: unknown; output: unknown; } }; `); }); @@ -354,12 +354,12 @@ describe('TypeScript', () => { expect(result.content).not.toBeSimilarStringTo(`/** My custom scalar */`); expect(result.content).toBeSimilarStringTo(` export type Scalars = { - ID: { input: string; output: string; } - String: { input: string; output: string; } - Boolean: { input: boolean; output: boolean; } - Int: { input: number; output: number; } - Float: { input: number; output: number; } - A: { input: any; output: any; } + ID: { input: string; output: string; } + String: { input: string; output: string; } + Boolean: { input: boolean; output: boolean; } + Int: { input: number; output: number; } + Float: { input: number; output: number; } + A: { input: unknown; output: unknown; } }; `); }); @@ -2170,7 +2170,7 @@ describe('TypeScript', () => { Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } - MyScalar: { input: any; output: any; } + MyScalar: { input: unknown; output: unknown; } };`); expect(result.content).toBeSimilarStringTo(` @@ -2297,7 +2297,7 @@ describe('TypeScript', () => { const result = (await plugin( schema, [], - { defaultScalarType: 'unknown' }, + { defaultScalarType: 'any' }, { outputFile: '' } )) as Types.ComplexPluginOutput; @@ -2308,7 +2308,7 @@ describe('TypeScript', () => { Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } - MyScalar: { input: unknown; output: unknown; } + MyScalar: { input: any; output: any; } };`); expect(result.content).toBeSimilarStringTo(`