Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .changeset/every-rooms-camp.md
Original file line number Diff line number Diff line change
@@ -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
8 changes: 4 additions & 4 deletions dev-test/gql-tag-operations/gql/gql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

Expand Down Expand Up @@ -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.
*/
Expand Down
6 changes: 5 additions & 1 deletion dev-test/gql-tag-operations/gql/graphql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 }>;

Expand All @@ -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' } },
],
},
},
Expand Down Expand Up @@ -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' } },
],
},
},
Expand Down
8 changes: 4 additions & 4 deletions dev-test/gql-tag-operations/graphql/gql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

Expand Down Expand Up @@ -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.
*/
Expand Down
6 changes: 5 additions & 1 deletion dev-test/gql-tag-operations/graphql/graphql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 }>;

Expand All @@ -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' } },
],
},
},
Expand Down Expand Up @@ -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' } },
],
},
},
Expand Down
1 change: 1 addition & 0 deletions dev-test/gql-tag-operations/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const LelFragment = graphql(/* GraphQL */ `
fragment Lel on Tweet {
id
body
date
}
`);

Expand Down
2 changes: 1 addition & 1 deletion dev-test/test-schema/resolvers-federation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
2 changes: 1 addition & 1 deletion packages/graphql-codegen-cli/tests/codegen.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
};`);
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -82,7 +82,7 @@ export interface RawConfig {
* 'path/to/file': {
* // plugins...
* config: {
* defaultScalarType: 'unknown'
* defaultScalarType: 'any'
* },
* },
* },
Expand Down
4 changes: 2 additions & 2 deletions packages/plugins/other/visitor-plugin-common/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ export function buildScalarsFromConfig(
schema: GraphQLSchema | undefined,
config: RawConfig,
defaultScalarsMapping: NormalizedScalarsMap = DEFAULT_SCALARS,
defaultScalarType = 'any'
defaultScalarType = 'unknown'
): ParsedScalarsMap {
return buildScalars(
schema,
Expand All @@ -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 = {};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
}
}
10 changes: 4 additions & 6 deletions packages/plugins/typescript/operations/src/visitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,16 +100,14 @@ export class TypeScriptDocumentsVisitor extends BaseDocumentsVisitor<
}),
ignoreEnumValuesFromSchema: getConfigValue(config.ignoreEnumValuesFromSchema, false),
futureProofEnums: getConfigValue(config.futureProofEnums, false),
maybeValue: getConfigValue(config.maybeValue, 'T | null'),
} as TypeScriptDocumentsParsedConfig,
schema
);

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 => ({
Expand All @@ -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}>`;
Expand Down Expand Up @@ -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) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When unknown and any is used, | null | undefined is not required.
However, the logic could be complex, so I'll bring back this condition and tests in another PR.

if (!typeNode.isNonNullable) {
typePart += ' | null | undefined';
}
continue;
Expand Down Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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 }
> };
"
`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand All @@ -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 =
Expand All @@ -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
};

Expand All @@ -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
};

Expand All @@ -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
};

Expand Down
Loading