From 53d0626ac5ebb0d4d90adb2912c2bcd1cbc9d860 Mon Sep 17 00:00:00 2001 From: Ben Durrant Date: Sun, 28 May 2023 19:10:12 +0100 Subject: [PATCH 01/24] create separate addTagTypes function --- packages/toolkit/src/query/apiTypes.ts | 20 +++++++++++++++++-- packages/toolkit/src/query/createApi.ts | 14 ++++++++----- .../toolkit/src/query/tests/createApi.test.ts | 6 +++--- 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/packages/toolkit/src/query/apiTypes.ts b/packages/toolkit/src/query/apiTypes.ts index e068250ce6..ca5831caf2 100644 --- a/packages/toolkit/src/query/apiTypes.ts +++ b/packages/toolkit/src/query/apiTypes.ts @@ -3,6 +3,10 @@ import type { EndpointBuilder, EndpointDefinition, UpdateDefinitions, + QueryDefinition, + ResultTypeFrom, + QueryArgFrom, + MutationDefinition, } from './endpointDefinitions' import type { UnionToIntersection, @@ -12,7 +16,7 @@ import type { import type { CoreModule } from './core/module' import type { CreateApiOptions } from './createApi' import type { BaseQueryFn } from './baseQueryTypes' -import type { CombinedState } from './core/apiState' +import type { CombinedState, MutationKeys, QueryKeys } from './core/apiState' import type { AnyAction } from '@reduxjs/toolkit' export interface ApiModules< @@ -91,7 +95,7 @@ export type Api< Enhancers > /** - *A function to enhance a generated API with additional information. Useful with code-generation. + * A function to enhance a generated API with additional information. Useful with code-generation. */ enhanceEndpoints< NewTagTypes extends string = never, @@ -116,4 +120,16 @@ export type Api< TagTypes | NewTagTypes, Enhancers > + /** + *A function to enhance a generated API with additional information. Useful with code-generation. + */ + addTagTypes( + ...addTagTypes: readonly NewTagTypes[] + ): Api< + BaseQuery, + UpdateDefinitions, + ReducerPath, + TagTypes | NewTagTypes, + Enhancers + > } diff --git a/packages/toolkit/src/query/createApi.ts b/packages/toolkit/src/query/createApi.ts index 5ff83e860e..910faf7f78 100644 --- a/packages/toolkit/src/query/createApi.ts +++ b/packages/toolkit/src/query/createApi.ts @@ -293,13 +293,17 @@ export function buildCreateApi, ...Module[]]>( const api = { injectEndpoints, + addTagTypes(...addTagTypes) { + for (const eT of addTagTypes) { + if (!optionsWithDefaults.tagTypes!.includes(eT as any)) { + ;(optionsWithDefaults.tagTypes as any[]).push(eT) + } + } + return api + }, enhanceEndpoints({ addTagTypes, endpoints }) { if (addTagTypes) { - for (const eT of addTagTypes) { - if (!optionsWithDefaults.tagTypes!.includes(eT as any)) { - ;(optionsWithDefaults.tagTypes as any[]).push(eT) - } - } + api.addTagTypes(...addTagTypes) } if (endpoints) { for (const [endpointName, partialDefinition] of Object.entries( diff --git a/packages/toolkit/src/query/tests/createApi.test.ts b/packages/toolkit/src/query/tests/createApi.test.ts index c735b51ebb..f39307eed1 100644 --- a/packages/toolkit/src/query/tests/createApi.test.ts +++ b/packages/toolkit/src/query/tests/createApi.test.ts @@ -1,6 +1,7 @@ import type { SerializedError } from '@reduxjs/toolkit' import { configureStore, createAction, createReducer } from '@reduxjs/toolkit' -import { vi, SpyInstance } from 'vitest' +import type { SpyInstance } from 'vitest' +import { vi } from 'vitest' import type { Api, MutationDefinition, @@ -445,8 +446,7 @@ describe('endpoint definition typings', () => { }) } - const enhanced = api.enhanceEndpoints({ - addTagTypes: ['new'], + const enhanced = api.addTagTypes('new').enhanceEndpoints({ endpoints: { query1: { providesTags: ['new'], From 93f8b4e4c58732f86f3f87005587ea164e06da90 Mon Sep 17 00:00:00 2001 From: Ben Durrant Date: Mon, 29 May 2023 00:35:46 +0100 Subject: [PATCH 02/24] add enhanceEndpoint --- packages/toolkit/src/query/apiTypes.ts | 90 ++++++++++++++++++- packages/toolkit/src/query/createApi.ts | 22 +++-- .../toolkit/src/query/endpointDefinitions.ts | 63 +++++++++++++ .../toolkit/src/query/tests/createApi.test.ts | 68 ++++++-------- 4 files changed, 191 insertions(+), 52 deletions(-) diff --git a/packages/toolkit/src/query/apiTypes.ts b/packages/toolkit/src/query/apiTypes.ts index ca5831caf2..bf255bcfe5 100644 --- a/packages/toolkit/src/query/apiTypes.ts +++ b/packages/toolkit/src/query/apiTypes.ts @@ -7,11 +7,14 @@ import type { ResultTypeFrom, QueryArgFrom, MutationDefinition, + AddTagTypes, + EnhanceEndpoint, } from './endpointDefinitions' import type { UnionToIntersection, NoInfer, WithRequiredProp, + Id, } from './tsHelpers' import type { CoreModule } from './core/module' import type { CreateApiOptions } from './createApi' @@ -96,6 +99,7 @@ export type Api< > /** * A function to enhance a generated API with additional information. Useful with code-generation. + * @deprecated use addTagTypes and/or enhanceEndpoint instead */ enhanceEndpoints< NewTagTypes extends string = never, @@ -127,9 +131,93 @@ export type Api< ...addTagTypes: readonly NewTagTypes[] ): Api< BaseQuery, - UpdateDefinitions, + AddTagTypes, ReducerPath, TagTypes | NewTagTypes, Enhancers > + + /** + *A function to enhance a generated API with additional information. Useful with code-generation. + */ + enhanceEndpoint< + QueryName extends QueryKeys, + QueryArg = QueryArgFrom, + ResultType = ResultTypeFrom + >( + queryName: QueryName, + partialDefinition: + | Partial< + QueryDefinition< + QueryArg, + BaseQuery, + TagTypes, + ResultType, + ReducerPath + > + > + | (( + definition: QueryDefinition< + QueryArg, + BaseQuery, + TagTypes, + ResultType, + ReducerPath + > + ) => void) + ): Api< + BaseQuery, + Id< + Omit & + Record< + QueryName, + EnhanceEndpoint + > + >, + ReducerPath, + TagTypes, + Enhancers + > + + /** + *A function to enhance a generated API with additional information. Useful with code-generation. + */ + enhanceEndpoint< + MutationName extends MutationKeys, + ResultType = ResultTypeFrom, + QueryArg = QueryArgFrom + >( + mutationName: MutationName, + partialDefinition: + | Partial< + MutationDefinition< + QueryArg, + BaseQuery, + TagTypes, + ResultType, + ReducerPath + > + > + | (( + definition: MutationDefinition< + QueryArg, + BaseQuery, + TagTypes, + ResultType, + ReducerPath + > + ) => void) + ): Api< + BaseQuery, + Id< + Omit & + Record< + MutationName, + EnhanceEndpoint + > + >, + ReducerPath, + TagTypes, + Enhancers + > } diff --git a/packages/toolkit/src/query/createApi.ts b/packages/toolkit/src/query/createApi.ts index 910faf7f78..afc667cc1a 100644 --- a/packages/toolkit/src/query/createApi.ts +++ b/packages/toolkit/src/query/createApi.ts @@ -301,6 +301,17 @@ export function buildCreateApi, ...Module[]]>( } return api }, + enhanceEndpoint(endpointName, partialDefinition) { + if (typeof partialDefinition === 'function') { + ;(partialDefinition as any)(context.endpointDefinitions[endpointName]) + } else { + Object.assign( + context.endpointDefinitions[endpointName] || {}, + partialDefinition + ) + } + return api + }, enhanceEndpoints({ addTagTypes, endpoints }) { if (addTagTypes) { api.addTagTypes(...addTagTypes) @@ -309,14 +320,7 @@ export function buildCreateApi, ...Module[]]>( for (const [endpointName, partialDefinition] of Object.entries( endpoints )) { - if (typeof partialDefinition === 'function') { - partialDefinition(context.endpointDefinitions[endpointName]) - } else { - Object.assign( - context.endpointDefinitions[endpointName] || {}, - partialDefinition - ) - } + ;(api.enhanceEndpoint as any)(endpointName, partialDefinition) } } return api @@ -363,6 +367,6 @@ export function buildCreateApi, ...Module[]]>( return api as any } - return api.injectEndpoints({ endpoints: options.endpoints as any }) + return api.injectEndpoints({ endpoints: options.endpoints as any }) as any } } diff --git a/packages/toolkit/src/query/endpointDefinitions.ts b/packages/toolkit/src/query/endpointDefinitions.ts index d0411f3ffb..d7b08140ee 100644 --- a/packages/toolkit/src/query/endpointDefinitions.ts +++ b/packages/toolkit/src/query/endpointDefinitions.ts @@ -811,6 +811,69 @@ export type OverrideResultType = > : never +export type AddTagTypes< + Definitions extends EndpointDefinitions, + NewTagTypes extends string +> = { + [K in keyof Definitions]: Definitions[K] extends QueryDefinition< + infer QueryArg, + infer BaseQuery, + any, + infer ResultType, + infer ReducerPath + > + ? QueryDefinition + : Definitions[K] extends MutationDefinition< + infer QueryArg, + infer BaseQuery, + any, + infer ResultType, + infer ReducerPath + > + ? MutationDefinition< + QueryArg, + BaseQuery, + NewTagTypes, + ResultType, + ReducerPath + > + : never +} + +export type EnhanceEndpoint< + Definition extends EndpointDefinition, + NewQueryArg, + NewResultType +> = Definition extends QueryDefinition< + any, + infer BaseQuery, + infer TagTypes, + any, + infer ReducerPath +> + ? QueryDefinition< + NewQueryArg, + BaseQuery, + TagTypes, + NewResultType, + ReducerPath + > + : Definition extends MutationDefinition< + any, + infer BaseQuery, + infer TagTypes, + any, + infer ReducerPath + > + ? MutationDefinition< + NewQueryArg, + BaseQuery, + TagTypes, + NewResultType, + ReducerPath + > + : never + export type UpdateDefinitions< Definitions extends EndpointDefinitions, NewTagTypes extends string, diff --git a/packages/toolkit/src/query/tests/createApi.test.ts b/packages/toolkit/src/query/tests/createApi.test.ts index f39307eed1..3953f7c581 100644 --- a/packages/toolkit/src/query/tests/createApi.test.ts +++ b/packages/toolkit/src/query/tests/createApi.test.ts @@ -489,7 +489,7 @@ describe('endpoint definition typings', () => { const storeRef = setupApiStore(api, undefined, { withoutTestLifecycles: true, }) - api.enhanceEndpoints({ + const enhanced = api.enhanceEndpoints({ endpoints: { query1: { query: (x) => { @@ -520,10 +520,10 @@ describe('endpoint definition typings', () => { }, }) - storeRef.store.dispatch(api.endpoints.query1.initiate('in1')) - storeRef.store.dispatch(api.endpoints.query2.initiate('in2')) - storeRef.store.dispatch(api.endpoints.mutation1.initiate('in1')) - storeRef.store.dispatch(api.endpoints.mutation2.initiate('in2')) + storeRef.store.dispatch(enhanced.endpoints.query1.initiate('in1')) + storeRef.store.dispatch(enhanced.endpoints.query2.initiate('in2')) + storeRef.store.dispatch(enhanced.endpoints.mutation1.initiate('in1')) + storeRef.store.dispatch(enhanced.endpoints.mutation2.initiate('in2')) expect(baseQuery.mock.calls).toEqual([ ['modified1', commonBaseQueryApi, undefined], @@ -543,36 +543,23 @@ describe('endpoint definition typings', () => { }), }) - type Transformed = { value: string } - - type Definitions = DefinitionsFromApi - type TagTypes = TagTypesFromApi - - type Q1Definition = OverrideResultType - type M1Definition = OverrideResultType< - Definitions['mutation1'], - Transformed - > - - type UpdatedDefitions = Omit & { - query1: Q1Definition - mutation1: M1Definition + const transformed = { + value: 'transformed', } - const enhancedApi = baseApi.enhanceEndpoints({ - endpoints: { - query1: { - transformResponse: (a, b, c) => ({ - value: 'transformed', - }), - }, - mutation1: { - transformResponse: (a, b, c) => ({ - value: 'transformed', - }), - }, - }, - }) + type Transformed = typeof transformed + + const enhancedApi = baseApi + .enhanceEndpoint('query1', { + transformResponse: () => transformed, + }) + // technically a cast, but works:tm: + .enhanceEndpoint<'mutation1', Transformed>( + 'mutation1', + (definition) => { + definition.transformResponse = () => transformed + } + ) const storeRef = setupApiStore(enhancedApi, undefined, { withoutTestLifecycles: true, @@ -581,21 +568,18 @@ describe('endpoint definition typings', () => { const queryResponse = await storeRef.store.dispatch( enhancedApi.endpoints.query1.initiate() ) - expect(queryResponse.data).toEqual({ value: 'transformed' }) - expectType | undefined>( - queryResponse.data - ) + expect(queryResponse.data).toEqual(transformed) + expectType(queryResponse.data) const mutationResponse = await storeRef.store.dispatch( enhancedApi.endpoints.mutation1.initiate() ) expectType< - | { data: Transformed | Promise } - | { error: FetchBaseQueryError | SerializedError } + { data: Transformed } | { error: FetchBaseQueryError | SerializedError } >(mutationResponse) - expect('data' in mutationResponse && mutationResponse.data).toEqual({ - value: 'transformed', - }) + expect('data' in mutationResponse && mutationResponse.data).toEqual( + transformed + ) }) }) }) From 60b2efc6a8c4a0a3893553841dda8e7badb276ac Mon Sep 17 00:00:00 2001 From: Ben Durrant Date: Mon, 29 May 2023 01:23:48 +0100 Subject: [PATCH 03/24] omit base api methods from module requirements --- packages/toolkit/src/query/apiTypes.ts | 17 +++++++++++++---- .../toolkit/src/query/core/buildInitiate.ts | 7 +++++-- .../src/query/core/buildMiddleware/types.ts | 7 +++++-- packages/toolkit/src/query/react/buildHooks.ts | 11 +++++++++-- 4 files changed, 32 insertions(+), 10 deletions(-) diff --git a/packages/toolkit/src/query/apiTypes.ts b/packages/toolkit/src/query/apiTypes.ts index bf255bcfe5..8644f75ad5 100644 --- a/packages/toolkit/src/query/apiTypes.ts +++ b/packages/toolkit/src/query/apiTypes.ts @@ -73,15 +73,13 @@ export interface ApiContext { hasRehydrationInfo: (action: AnyAction) => boolean } -export type Api< +export type BaseApiMethods< BaseQuery extends BaseQueryFn, Definitions extends EndpointDefinitions, ReducerPath extends string, TagTypes extends string, Enhancers extends ModuleName = CoreModule -> = UnionToIntersection< - ApiModules[Enhancers] -> & { +> = { /** * A function to inject the endpoints into the original API, but also give you that same API with correct types for these endpoints back. Useful with code-splitting. */ @@ -221,3 +219,14 @@ export type Api< Enhancers > } + +export type Api< + BaseQuery extends BaseQueryFn, + Definitions extends EndpointDefinitions, + ReducerPath extends string, + TagTypes extends string, + Enhancers extends ModuleName = CoreModule +> = UnionToIntersection< + ApiModules[Enhancers] +> & + BaseApiMethods diff --git a/packages/toolkit/src/query/core/buildInitiate.ts b/packages/toolkit/src/query/core/buildInitiate.ts index a26aaf0b2a..40714f18f6 100644 --- a/packages/toolkit/src/query/core/buildInitiate.ts +++ b/packages/toolkit/src/query/core/buildInitiate.ts @@ -10,7 +10,7 @@ import type { QueryThunk, MutationThunk, QueryThunkArg } from './buildThunks' import type { AnyAction, ThunkAction, SerializedError } from '@reduxjs/toolkit' import type { SubscriptionOptions, RootState } from './apiState' import type { InternalSerializeQueryArgs } from '../defaultSerializeQueryArgs' -import type { Api, ApiContext } from '../apiTypes' +import type { Api, ApiContext, BaseApiMethods } from '../apiTypes' import type { ApiEndpointQuery } from './module' import type { BaseQueryError, QueryReturnValue } from '../baseQueryTypes' import type { QueryResultSelectorResult } from './buildSelectors' @@ -193,7 +193,10 @@ export function buildInitiate({ serializeQueryArgs: InternalSerializeQueryArgs queryThunk: QueryThunk mutationThunk: MutationThunk - api: Api + api: Omit< + Api, + keyof BaseApiMethods + > context: ApiContext }) { const runningQueries: Map< diff --git a/packages/toolkit/src/query/core/buildMiddleware/types.ts b/packages/toolkit/src/query/core/buildMiddleware/types.ts index 78e6a53e90..9b2b08dd9e 100644 --- a/packages/toolkit/src/query/core/buildMiddleware/types.ts +++ b/packages/toolkit/src/query/core/buildMiddleware/types.ts @@ -7,7 +7,7 @@ import type { ThunkDispatch, } from '@reduxjs/toolkit' -import type { Api, ApiContext } from '../../apiTypes' +import type { Api, ApiContext, BaseApiMethods } from '../../apiTypes' import type { AssertTagTypes, EndpointDefinitions, @@ -41,7 +41,10 @@ export interface BuildMiddlewareInput< context: ApiContext queryThunk: QueryThunk mutationThunk: MutationThunk - api: Api + api: Omit< + Api, + keyof BaseApiMethods + > assertTagType: AssertTagTypes } diff --git a/packages/toolkit/src/query/react/buildHooks.ts b/packages/toolkit/src/query/react/buildHooks.ts index 3b764d31ef..a22cfa89d9 100644 --- a/packages/toolkit/src/query/react/buildHooks.ts +++ b/packages/toolkit/src/query/react/buildHooks.ts @@ -36,7 +36,11 @@ import type { } from '@reduxjs/toolkit/dist/query/core/buildInitiate' import type { SerializeQueryArgs } from '@reduxjs/toolkit/dist/query/defaultSerializeQueryArgs' import { shallowEqual } from 'react-redux' -import type { Api, ApiContext } from '@reduxjs/toolkit/dist/query/apiTypes' +import type { + Api, + ApiContext, + BaseApiMethods, +} from '@reduxjs/toolkit/dist/query/apiTypes' import type { Id, NoInfer, @@ -587,7 +591,10 @@ export function buildHooks({ serializeQueryArgs, context, }: { - api: Api + api: Omit< + Api, + keyof BaseApiMethods + > moduleOptions: Required serializeQueryArgs: SerializeQueryArgs context: ApiContext From ee0220223e77154e1dd4bfa6cc8efbebc67a9746 Mon Sep 17 00:00:00 2001 From: Ben Durrant Date: Thu, 1 Jun 2023 19:52:09 +0100 Subject: [PATCH 04/24] update codegen and type tests --- .../rtk-query-codegen-openapi/src/codegen.ts | 53 +- .../generateEndpoints.test.ts.snap | 520 +++++++++--------- .../test/tmp/emptyApi.ts | 6 + .../rtk-query-codegen-openapi/test/tmp/out.ts | 8 + .../toolkit/src/query/tests/createApi.test.ts | 106 ++-- 5 files changed, 332 insertions(+), 361 deletions(-) create mode 100644 packages/rtk-query-codegen-openapi/test/tmp/emptyApi.ts create mode 100644 packages/rtk-query-codegen-openapi/test/tmp/out.ts diff --git a/packages/rtk-query-codegen-openapi/src/codegen.ts b/packages/rtk-query-codegen-openapi/src/codegen.ts index 09518f54d3..ab727c02be 100644 --- a/packages/rtk-query-codegen-openapi/src/codegen.ts +++ b/packages/rtk-query-codegen-openapi/src/codegen.ts @@ -64,33 +64,31 @@ export function generateCreateApiCall({ true ); if (tag) { - const enhanceEndpointsObjectLiteralExpression = factory.createObjectLiteralExpression( - [factory.createShorthandPropertyAssignment(factory.createIdentifier('addTagTypes'), undefined)], - true - ) return factory.createVariableStatement( undefined, factory.createVariableDeclarationList( - [factory.createVariableDeclaration( - factory.createIdentifier("injectedRtkApi"), - undefined, - undefined, - factory.createCallExpression( - factory.createPropertyAccessExpression( - factory.createCallExpression( - factory.createPropertyAccessExpression( - factory.createIdentifier("api"), - factory.createIdentifier("enhanceEndpoints") + [ + factory.createVariableDeclaration( + factory.createIdentifier('injectedRtkApi'), + undefined, + undefined, + factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier('api'), + factory.createIdentifier('addTagTypes') + ), + undefined, + [factory.createSpreadElement(factory.createIdentifier('addTagTypes'))] ), - undefined, - [enhanceEndpointsObjectLiteralExpression] + factory.createIdentifier('injectEndpoints') ), - factory.createIdentifier("injectEndpoints") - ), - undefined, - [injectEndpointsObjectLiteralExpression] - ) - )], + undefined, + [injectEndpointsObjectLiteralExpression] + ) + ), + ], ts.NodeFlags.Const ) ); @@ -145,7 +143,7 @@ export function generateEndpointDefinition({ factory.createIdentifier(type === 'query' ? 'providesTags' : 'invalidatesTags'), factory.createArrayLiteralExpression(tags.map((tag) => factory.createStringLiteral(tag), false)) ) - ) + ); } return factory.createPropertyAssignment( factory.createIdentifier(operationName), @@ -153,13 +151,8 @@ export function generateEndpointDefinition({ factory.createCallExpression( factory.createPropertyAccessExpression(endpointBuilder, factory.createIdentifier(type)), [Response, QueryArg], - [ - factory.createObjectLiteralExpression( - objectProperties, - true - ), - ] - ), + [factory.createObjectLiteralExpression(objectProperties, true)] + ) ); } diff --git a/packages/rtk-query-codegen-openapi/test/__snapshots__/generateEndpoints.test.ts.snap b/packages/rtk-query-codegen-openapi/test/__snapshots__/generateEndpoints.test.ts.snap index 1f01cf2155..3cbab7ab9e 100644 --- a/packages/rtk-query-codegen-openapi/test/__snapshots__/generateEndpoints.test.ts.snap +++ b/packages/rtk-query-codegen-openapi/test/__snapshots__/generateEndpoints.test.ts.snap @@ -674,143 +674,135 @@ export const { useGetApiV1AnimalsQuery } = injectedRtkApi; exports[`yaml parsing should be able to use read a yaml file 1`] = ` import { api } from './tmp/emptyApi'; export const addTagTypes = ['pet', 'store', 'user'] as const; -const injectedRtkApi = api - .enhanceEndpoints({ - addTagTypes, - }) - .injectEndpoints({ - endpoints: (build) => ({ - updatePet: build.mutation({ - query: (queryArg) => ({ - url: \`/pet\`, - method: 'PUT', - body: queryArg.pet, - }), - invalidatesTags: ['pet'], - }), - addPet: build.mutation({ - query: (queryArg) => ({ - url: \`/pet\`, - method: 'POST', - body: queryArg.pet, - }), - invalidatesTags: ['pet'], - }), - findPetsByStatus: build.query({ - query: (queryArg) => ({ - url: \`/pet/findByStatus\`, - params: { status: queryArg.status }, - }), - providesTags: ['pet'], - }), - findPetsByTags: build.query({ - query: (queryArg) => ({ - url: \`/pet/findByTags\`, - params: { tags: queryArg.tags }, - }), - providesTags: ['pet'], - }), - getPetById: build.query({ - query: (queryArg) => ({ url: \`/pet/\${queryArg.petId}\` }), - providesTags: ['pet'], - }), - updatePetWithForm: build.mutation({ - query: (queryArg) => ({ - url: \`/pet/\${queryArg.petId}\`, - method: 'POST', - params: { name: queryArg.name, status: queryArg.status }, - }), - invalidatesTags: ['pet'], - }), - deletePet: build.mutation({ - query: (queryArg) => ({ - url: \`/pet/\${queryArg.petId}\`, - method: 'DELETE', - headers: { api_key: queryArg.apiKey }, - }), - invalidatesTags: ['pet'], +const injectedRtkApi = api.addTagTypes(...addTagTypes).injectEndpoints({ + endpoints: (build) => ({ + updatePet: build.mutation({ + query: (queryArg) => ({ url: \`/pet\`, method: 'PUT', body: queryArg.pet }), + invalidatesTags: ['pet'], + }), + addPet: build.mutation({ + query: (queryArg) => ({ + url: \`/pet\`, + method: 'POST', + body: queryArg.pet, }), - uploadFile: build.mutation({ - query: (queryArg) => ({ - url: \`/pet/\${queryArg.petId}/uploadImage\`, - method: 'POST', - body: queryArg.body, - params: { additionalMetadata: queryArg.additionalMetadata }, - }), - invalidatesTags: ['pet'], + invalidatesTags: ['pet'], + }), + findPetsByStatus: build.query({ + query: (queryArg) => ({ + url: \`/pet/findByStatus\`, + params: { status: queryArg.status }, }), - getInventory: build.query({ - query: () => ({ url: \`/store/inventory\` }), - providesTags: ['store'], + providesTags: ['pet'], + }), + findPetsByTags: build.query({ + query: (queryArg) => ({ + url: \`/pet/findByTags\`, + params: { tags: queryArg.tags }, }), - placeOrder: build.mutation({ - query: (queryArg) => ({ - url: \`/store/order\`, - method: 'POST', - body: queryArg.order, - }), - invalidatesTags: ['store'], + providesTags: ['pet'], + }), + getPetById: build.query({ + query: (queryArg) => ({ url: \`/pet/\${queryArg.petId}\` }), + providesTags: ['pet'], + }), + updatePetWithForm: build.mutation({ + query: (queryArg) => ({ + url: \`/pet/\${queryArg.petId}\`, + method: 'POST', + params: { name: queryArg.name, status: queryArg.status }, }), - getOrderById: build.query({ - query: (queryArg) => ({ url: \`/store/order/\${queryArg.orderId}\` }), - providesTags: ['store'], + invalidatesTags: ['pet'], + }), + deletePet: build.mutation({ + query: (queryArg) => ({ + url: \`/pet/\${queryArg.petId}\`, + method: 'DELETE', + headers: { api_key: queryArg.apiKey }, }), - deleteOrder: build.mutation({ - query: (queryArg) => ({ - url: \`/store/order/\${queryArg.orderId}\`, - method: 'DELETE', - }), - invalidatesTags: ['store'], + invalidatesTags: ['pet'], + }), + uploadFile: build.mutation({ + query: (queryArg) => ({ + url: \`/pet/\${queryArg.petId}/uploadImage\`, + method: 'POST', + body: queryArg.body, + params: { additionalMetadata: queryArg.additionalMetadata }, }), - createUser: build.mutation({ - query: (queryArg) => ({ - url: \`/user\`, - method: 'POST', - body: queryArg.user, - }), - invalidatesTags: ['user'], + invalidatesTags: ['pet'], + }), + getInventory: build.query({ + query: () => ({ url: \`/store/inventory\` }), + providesTags: ['store'], + }), + placeOrder: build.mutation({ + query: (queryArg) => ({ + url: \`/store/order\`, + method: 'POST', + body: queryArg.order, }), - createUsersWithListInput: build.mutation({ - query: (queryArg) => ({ - url: \`/user/createWithList\`, - method: 'POST', - body: queryArg.body, - }), - invalidatesTags: ['user'], + invalidatesTags: ['store'], + }), + getOrderById: build.query({ + query: (queryArg) => ({ url: \`/store/order/\${queryArg.orderId}\` }), + providesTags: ['store'], + }), + deleteOrder: build.mutation({ + query: (queryArg) => ({ + url: \`/store/order/\${queryArg.orderId}\`, + method: 'DELETE', }), - loginUser: build.query({ - query: (queryArg) => ({ - url: \`/user/login\`, - params: { username: queryArg.username, password: queryArg.password }, - }), - providesTags: ['user'], + invalidatesTags: ['store'], + }), + createUser: build.mutation({ + query: (queryArg) => ({ + url: \`/user\`, + method: 'POST', + body: queryArg.user, }), - logoutUser: build.query({ - query: () => ({ url: \`/user/logout\` }), - providesTags: ['user'], + invalidatesTags: ['user'], + }), + createUsersWithListInput: build.mutation({ + query: (queryArg) => ({ + url: \`/user/createWithList\`, + method: 'POST', + body: queryArg.body, }), - getUserByName: build.query({ - query: (queryArg) => ({ url: \`/user/\${queryArg.username}\` }), - providesTags: ['user'], + invalidatesTags: ['user'], + }), + loginUser: build.query({ + query: (queryArg) => ({ + url: \`/user/login\`, + params: { username: queryArg.username, password: queryArg.password }, }), - updateUser: build.mutation({ - query: (queryArg) => ({ - url: \`/user/\${queryArg.username}\`, - method: 'PUT', - body: queryArg.user, - }), - invalidatesTags: ['user'], + providesTags: ['user'], + }), + logoutUser: build.query({ + query: () => ({ url: \`/user/logout\` }), + providesTags: ['user'], + }), + getUserByName: build.query({ + query: (queryArg) => ({ url: \`/user/\${queryArg.username}\` }), + providesTags: ['user'], + }), + updateUser: build.mutation({ + query: (queryArg) => ({ + url: \`/user/\${queryArg.username}\`, + method: 'PUT', + body: queryArg.user, }), - deleteUser: build.mutation({ - query: (queryArg) => ({ - url: \`/user/\${queryArg.username}\`, - method: 'DELETE', - }), - invalidatesTags: ['user'], + invalidatesTags: ['user'], + }), + deleteUser: build.mutation({ + query: (queryArg) => ({ + url: \`/user/\${queryArg.username}\`, + method: 'DELETE', }), + invalidatesTags: ['user'], }), - overrideExisting: false, - }); + }), + overrideExisting: false, +}); export { injectedRtkApi as enhancedApi }; export type UpdatePetApiResponse = /** status 200 Successful operation */ Pet; export type UpdatePetApiArg = { @@ -979,31 +971,27 @@ export const { exports[`yaml parsing should generate params with non quoted keys if they don't contain special characters 1`] = ` import { api } from './tmp/emptyApi'; export const addTagTypes = ['StructureDefinition'] as const; -const injectedRtkApi = api - .enhanceEndpoints({ - addTagTypes, - }) - .injectEndpoints({ - endpoints: (build) => ({ - getStructureDefinition: build.query({ - query: (queryArg) => ({ - url: \`/StructureDefinition\`, - params: { - foo: queryArg.foo, - _foo: queryArg._foo, - '-bar-bar': queryArg['-bar-bar'], - _bar_bar: queryArg._bar_bar, - 'foo:bar-foo.bar/foo': queryArg['foo:bar-foo.bar/foo'], - foo_bar: queryArg.fooBar, - namingConflict: queryArg.namingConflict, - naming_conflict: queryArg.naming_conflict, - }, - }), - providesTags: ['StructureDefinition'], - }), +const injectedRtkApi = api.addTagTypes(...addTagTypes).injectEndpoints({ + endpoints: (build) => ({ + getStructureDefinition: build.query({ + query: (queryArg) => ({ + url: \`/StructureDefinition\`, + params: { + foo: queryArg.foo, + _foo: queryArg._foo, + '-bar-bar': queryArg['-bar-bar'], + _bar_bar: queryArg._bar_bar, + 'foo:bar-foo.bar/foo': queryArg['foo:bar-foo.bar/foo'], + foo_bar: queryArg.fooBar, + namingConflict: queryArg.namingConflict, + naming_conflict: queryArg.naming_conflict, + }, + }), + providesTags: ['StructureDefinition'], }), - overrideExisting: false, - }); + }), + overrideExisting: false, +}); export { injectedRtkApi as enhancedApi }; export type GetStructureDefinitionApiResponse = unknown; export type GetStructureDefinitionApiArg = { @@ -1031,143 +1019,135 @@ export const { useGetStructureDefinitionQuery } = injectedRtkApi; exports[`yaml parsing should parse a yaml schema from a URL 1`] = ` import { api } from './tmp/emptyApi'; export const addTagTypes = ['pet', 'store', 'user'] as const; -const injectedRtkApi = api - .enhanceEndpoints({ - addTagTypes, - }) - .injectEndpoints({ - endpoints: (build) => ({ - updatePet: build.mutation({ - query: (queryArg) => ({ - url: \`/pet\`, - method: 'PUT', - body: queryArg.pet, - }), - invalidatesTags: ['pet'], - }), - addPet: build.mutation({ - query: (queryArg) => ({ - url: \`/pet\`, - method: 'POST', - body: queryArg.pet, - }), - invalidatesTags: ['pet'], - }), - findPetsByStatus: build.query({ - query: (queryArg) => ({ - url: \`/pet/findByStatus\`, - params: { status: queryArg.status }, - }), - providesTags: ['pet'], - }), - findPetsByTags: build.query({ - query: (queryArg) => ({ - url: \`/pet/findByTags\`, - params: { tags: queryArg.tags }, - }), - providesTags: ['pet'], - }), - getPetById: build.query({ - query: (queryArg) => ({ url: \`/pet/\${queryArg.petId}\` }), - providesTags: ['pet'], - }), - updatePetWithForm: build.mutation({ - query: (queryArg) => ({ - url: \`/pet/\${queryArg.petId}\`, - method: 'POST', - params: { name: queryArg.name, status: queryArg.status }, - }), - invalidatesTags: ['pet'], - }), - deletePet: build.mutation({ - query: (queryArg) => ({ - url: \`/pet/\${queryArg.petId}\`, - method: 'DELETE', - headers: { api_key: queryArg.apiKey }, - }), - invalidatesTags: ['pet'], +const injectedRtkApi = api.addTagTypes(...addTagTypes).injectEndpoints({ + endpoints: (build) => ({ + updatePet: build.mutation({ + query: (queryArg) => ({ url: \`/pet\`, method: 'PUT', body: queryArg.pet }), + invalidatesTags: ['pet'], + }), + addPet: build.mutation({ + query: (queryArg) => ({ + url: \`/pet\`, + method: 'POST', + body: queryArg.pet, }), - uploadFile: build.mutation({ - query: (queryArg) => ({ - url: \`/pet/\${queryArg.petId}/uploadImage\`, - method: 'POST', - body: queryArg.body, - params: { additionalMetadata: queryArg.additionalMetadata }, - }), - invalidatesTags: ['pet'], + invalidatesTags: ['pet'], + }), + findPetsByStatus: build.query({ + query: (queryArg) => ({ + url: \`/pet/findByStatus\`, + params: { status: queryArg.status }, }), - getInventory: build.query({ - query: () => ({ url: \`/store/inventory\` }), - providesTags: ['store'], + providesTags: ['pet'], + }), + findPetsByTags: build.query({ + query: (queryArg) => ({ + url: \`/pet/findByTags\`, + params: { tags: queryArg.tags }, }), - placeOrder: build.mutation({ - query: (queryArg) => ({ - url: \`/store/order\`, - method: 'POST', - body: queryArg.order, - }), - invalidatesTags: ['store'], + providesTags: ['pet'], + }), + getPetById: build.query({ + query: (queryArg) => ({ url: \`/pet/\${queryArg.petId}\` }), + providesTags: ['pet'], + }), + updatePetWithForm: build.mutation({ + query: (queryArg) => ({ + url: \`/pet/\${queryArg.petId}\`, + method: 'POST', + params: { name: queryArg.name, status: queryArg.status }, }), - getOrderById: build.query({ - query: (queryArg) => ({ url: \`/store/order/\${queryArg.orderId}\` }), - providesTags: ['store'], + invalidatesTags: ['pet'], + }), + deletePet: build.mutation({ + query: (queryArg) => ({ + url: \`/pet/\${queryArg.petId}\`, + method: 'DELETE', + headers: { api_key: queryArg.apiKey }, }), - deleteOrder: build.mutation({ - query: (queryArg) => ({ - url: \`/store/order/\${queryArg.orderId}\`, - method: 'DELETE', - }), - invalidatesTags: ['store'], + invalidatesTags: ['pet'], + }), + uploadFile: build.mutation({ + query: (queryArg) => ({ + url: \`/pet/\${queryArg.petId}/uploadImage\`, + method: 'POST', + body: queryArg.body, + params: { additionalMetadata: queryArg.additionalMetadata }, }), - createUser: build.mutation({ - query: (queryArg) => ({ - url: \`/user\`, - method: 'POST', - body: queryArg.user, - }), - invalidatesTags: ['user'], + invalidatesTags: ['pet'], + }), + getInventory: build.query({ + query: () => ({ url: \`/store/inventory\` }), + providesTags: ['store'], + }), + placeOrder: build.mutation({ + query: (queryArg) => ({ + url: \`/store/order\`, + method: 'POST', + body: queryArg.order, }), - createUsersWithListInput: build.mutation({ - query: (queryArg) => ({ - url: \`/user/createWithList\`, - method: 'POST', - body: queryArg.body, - }), - invalidatesTags: ['user'], + invalidatesTags: ['store'], + }), + getOrderById: build.query({ + query: (queryArg) => ({ url: \`/store/order/\${queryArg.orderId}\` }), + providesTags: ['store'], + }), + deleteOrder: build.mutation({ + query: (queryArg) => ({ + url: \`/store/order/\${queryArg.orderId}\`, + method: 'DELETE', }), - loginUser: build.query({ - query: (queryArg) => ({ - url: \`/user/login\`, - params: { username: queryArg.username, password: queryArg.password }, - }), - providesTags: ['user'], + invalidatesTags: ['store'], + }), + createUser: build.mutation({ + query: (queryArg) => ({ + url: \`/user\`, + method: 'POST', + body: queryArg.user, }), - logoutUser: build.query({ - query: () => ({ url: \`/user/logout\` }), - providesTags: ['user'], + invalidatesTags: ['user'], + }), + createUsersWithListInput: build.mutation({ + query: (queryArg) => ({ + url: \`/user/createWithList\`, + method: 'POST', + body: queryArg.body, }), - getUserByName: build.query({ - query: (queryArg) => ({ url: \`/user/\${queryArg.username}\` }), - providesTags: ['user'], + invalidatesTags: ['user'], + }), + loginUser: build.query({ + query: (queryArg) => ({ + url: \`/user/login\`, + params: { username: queryArg.username, password: queryArg.password }, }), - updateUser: build.mutation({ - query: (queryArg) => ({ - url: \`/user/\${queryArg.username}\`, - method: 'PUT', - body: queryArg.user, - }), - invalidatesTags: ['user'], + providesTags: ['user'], + }), + logoutUser: build.query({ + query: () => ({ url: \`/user/logout\` }), + providesTags: ['user'], + }), + getUserByName: build.query({ + query: (queryArg) => ({ url: \`/user/\${queryArg.username}\` }), + providesTags: ['user'], + }), + updateUser: build.mutation({ + query: (queryArg) => ({ + url: \`/user/\${queryArg.username}\`, + method: 'PUT', + body: queryArg.user, }), - deleteUser: build.mutation({ - query: (queryArg) => ({ - url: \`/user/\${queryArg.username}\`, - method: 'DELETE', - }), - invalidatesTags: ['user'], + invalidatesTags: ['user'], + }), + deleteUser: build.mutation({ + query: (queryArg) => ({ + url: \`/user/\${queryArg.username}\`, + method: 'DELETE', }), + invalidatesTags: ['user'], }), - overrideExisting: false, - }); + }), + overrideExisting: false, +}); export { injectedRtkApi as enhancedApi }; export type UpdatePetApiResponse = /** status 200 Successful operation */ Pet; export type UpdatePetApiArg = { diff --git a/packages/rtk-query-codegen-openapi/test/tmp/emptyApi.ts b/packages/rtk-query-codegen-openapi/test/tmp/emptyApi.ts new file mode 100644 index 0000000000..60cbd48736 --- /dev/null +++ b/packages/rtk-query-codegen-openapi/test/tmp/emptyApi.ts @@ -0,0 +1,6 @@ +import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; + +export const api = createApi({ + baseQuery: fetchBaseQuery({}), + endpoints: () => ({}), +}); diff --git a/packages/rtk-query-codegen-openapi/test/tmp/out.ts b/packages/rtk-query-codegen-openapi/test/tmp/out.ts new file mode 100644 index 0000000000..ff75963809 --- /dev/null +++ b/packages/rtk-query-codegen-openapi/test/tmp/out.ts @@ -0,0 +1,8 @@ +import { api } from './emptyApi'; +export const addTagTypes = [] as const; +const injectedRtkApi = api.addTagTypes(...addTagTypes).injectEndpoints({ + endpoints: (build) => ({}), + overrideExisting: false, +}); +export { injectedRtkApi as enhancedApi }; +export const {} = injectedRtkApi; diff --git a/packages/toolkit/src/query/tests/createApi.test.ts b/packages/toolkit/src/query/tests/createApi.test.ts index 3953f7c581..e6dbb1eed7 100644 --- a/packages/toolkit/src/query/tests/createApi.test.ts +++ b/packages/toolkit/src/query/tests/createApi.test.ts @@ -432,31 +432,25 @@ describe('endpoint definition typings', () => { }) // only type-test this part if (2 > 1) { - api.enhanceEndpoints({ - endpoints: { - query1: { - // @ts-expect-error - providesTags: ['new'], - }, - query2: { - // @ts-expect-error - providesTags: ['missing'], - }, - }, + // @ts-expect-error + api.enhanceEndpoint('query1', { + providesTags: ['new'], + }) + // @ts-expect-error + api.enhanceEndpoint('query2', { + providesTags: ['missing'], }) } - const enhanced = api.addTagTypes('new').enhanceEndpoints({ - endpoints: { - query1: { - providesTags: ['new'], - }, - query2: { - // @ts-expect-error - providesTags: ['missing'], - }, - }, - }) + // @ts-expect-error + const enhanced = api + .addTagTypes('new') + .enhanceEndpoint('query1', { + providesTags: ['new'], + }) + .enhanceEndpoint('query2', { + providesTags: ['missing'], + }) storeRef.store.dispatch(api.endpoints.query1.initiate('in1')) await waitMs(1) @@ -470,17 +464,12 @@ describe('endpoint definition typings', () => { // only type-test this part if (2 > 1) { - enhanced.enhanceEndpoints({ - endpoints: { - query1: { - // returned `enhanced` api contains "new" enitityType - providesTags: ['new'], - }, - query2: { - // @ts-expect-error - providesTags: ['missing'], - }, - }, + enhanced.enhanceEndpoint('query1', { + providesTags: ['new'], // tag was added + }) + // @ts-expect-error + enhanced.enhanceEndpoint('query2', { + providesTags: ['missing'], }) } }) @@ -489,36 +478,31 @@ describe('endpoint definition typings', () => { const storeRef = setupApiStore(api, undefined, { withoutTestLifecycles: true, }) - const enhanced = api.enhanceEndpoints({ - endpoints: { - query1: { - query: (x) => { - expectExactType('in1' as const)(x) - return 'modified1' - }, - }, - query2(definition) { - definition.query = (x) => { - expectExactType('in2' as const)(x) - return 'modified2' - } - }, - mutation1: { - query: (x) => { - expectExactType('in1' as const)(x) - return 'modified1' - }, + const enhanced = api + .enhanceEndpoint('query1', { + query: (x) => { + expectExactType('in1' as const)(x) + return 'modified1' }, - mutation2(definition) { - definition.query = (x) => { - expectExactType('in2' as const)(x) - return 'modified2' - } + }) + .enhanceEndpoint('query2', function query2(definition) { + definition.query = (x) => { + expectExactType('in2' as const)(x) + return 'modified2' + } + }) + .enhanceEndpoint('mutation1', { + query: (x) => { + expectExactType('in1' as const)(x) + return 'modified1' }, - // @ts-expect-error - nonExisting: {}, - }, - }) + }) + .enhanceEndpoint('mutation2', function mutation2(definition) { + definition.query = (x) => { + expectExactType('in2' as const)(x) + return 'modified2' + } + }) storeRef.store.dispatch(enhanced.endpoints.query1.initiate('in1')) storeRef.store.dispatch(enhanced.endpoints.query2.initiate('in2')) From 8d2b42ec7dd2d7345d44d26e068f1e9297c5dc63 Mon Sep 17 00:00:00 2001 From: Ben Durrant Date: Thu, 1 Jun 2023 23:00:37 +0100 Subject: [PATCH 05/24] update codemod deps --- packages/rtk-codemods/package.json | 12 +- yarn.lock | 251 +++++++++++++++++++++-------- 2 files changed, 186 insertions(+), 77 deletions(-) diff --git a/packages/rtk-codemods/package.json b/packages/rtk-codemods/package.json index 7f1fa0b7a9..d6e189b8ee 100644 --- a/packages/rtk-codemods/package.json +++ b/packages/rtk-codemods/package.json @@ -22,20 +22,20 @@ "codemod" ], "dependencies": { - "@types/jest": "^27", - "@types/jscodeshift": "^0.11.5", + "@types/jest": "^29", + "@types/jscodeshift": "^0.11.6", "codemod-cli": "^3.2.0", - "ts-node": "10.4.0", - "typescript": "^4.8.0" + "ts-node": "^10.4.0", + "typescript": "^5" }, "devDependencies": { "eslint": "^7.25.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-node": "^11.1.0", "eslint-plugin-prettier": "^3.4.0", - "jest": "^27", + "jest": "^29", "prettier": "^2.2.1", - "ts-jest": "^27" + "ts-jest": "^29" }, "engines": { "node": ">= 14" diff --git a/yarn.lock b/yarn.lock index 054ecbd38a..61c8567935 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5752,6 +5752,15 @@ __metadata: languageName: node linkType: hard +"@jest/expect-utils@npm:^29.5.0": + version: 29.5.0 + resolution: "@jest/expect-utils@npm:29.5.0" + dependencies: + jest-get-type: ^29.4.3 + checksum: c46fb677c88535cf83cf29f0a5b1f376c6a1109ddda266ad7da1a9cbc53cb441fa402dd61fc7b111ffc99603c11a9b3357ee41a1c0e035a58830bcb360871476 + languageName: node + linkType: hard + "@jest/expect@npm:^29.3.1": version: 29.3.1 resolution: "@jest/expect@npm:29.3.1" @@ -5906,6 +5915,15 @@ __metadata: languageName: node linkType: hard +"@jest/schemas@npm:^29.4.3": + version: 29.4.3 + resolution: "@jest/schemas@npm:29.4.3" + dependencies: + "@sinclair/typebox": ^0.25.16 + checksum: ac754e245c19dc39e10ebd41dce09040214c96a4cd8efa143b82148e383e45128f24599195ab4f01433adae4ccfbe2db6574c90db2862ccd8551a86704b5bebd + languageName: node + linkType: hard + "@jest/source-map@npm:^27.5.1": version: 27.5.1 resolution: "@jest/source-map@npm:27.5.1" @@ -6111,6 +6129,20 @@ __metadata: languageName: node linkType: hard +"@jest/types@npm:^29.5.0": + version: 29.5.0 + resolution: "@jest/types@npm:29.5.0" + dependencies: + "@jest/schemas": ^29.4.3 + "@types/istanbul-lib-coverage": ^2.0.0 + "@types/istanbul-reports": ^3.0.0 + "@types/node": "*" + "@types/yargs": ^17.0.8 + chalk: ^4.0.0 + checksum: 1811f94b19cf8a9460a289c4f056796cfc373480e0492692a6125a553cd1a63824bd846d7bb78820b7b6f758f6dd3c2d4558293bb676d541b2fa59c70fdf9d39 + languageName: node + linkType: hard + "@jridgewell/gen-mapping@npm:^0.1.0": version: 0.1.1 resolution: "@jridgewell/gen-mapping@npm:0.1.1" @@ -6688,18 +6720,18 @@ __metadata: version: 0.0.0-use.local resolution: "@reduxjs/rtk-codemods@workspace:packages/rtk-codemods" dependencies: - "@types/jest": ^27 - "@types/jscodeshift": ^0.11.5 + "@types/jest": ^29 + "@types/jscodeshift": ^0.11.6 codemod-cli: ^3.2.0 eslint: ^7.25.0 eslint-config-prettier: ^8.3.0 eslint-plugin-node: ^11.1.0 eslint-plugin-prettier: ^3.4.0 - jest: ^27 + jest: ^29 prettier: ^2.2.1 - ts-jest: ^27 - ts-node: 10.4.0 - typescript: ^4.8.0 + ts-jest: ^29 + ts-node: ^10.4.0 + typescript: ^5 bin: rtk-codemods: ./bin/cli.js languageName: unknown @@ -7078,6 +7110,13 @@ __metadata: languageName: node linkType: hard +"@sinclair/typebox@npm:^0.25.16": + version: 0.25.24 + resolution: "@sinclair/typebox@npm:0.25.24" + checksum: 10219c58f40b8414c50b483b0550445e9710d4fe7b2c4dccb9b66533dd90ba8e024acc776026cebe81e87f06fa24b07fdd7bc30dd277eb9cc386ec50151a3026 + languageName: node + linkType: hard + "@sindresorhus/is@npm:^0.14.0": version: 0.14.0 resolution: "@sindresorhus/is@npm:0.14.0" @@ -7941,6 +7980,16 @@ __metadata: languageName: node linkType: hard +"@types/jest@npm:^29": + version: 29.5.2 + resolution: "@types/jest@npm:29.5.2" + dependencies: + expect: ^29.0.0 + pretty-format: ^29.0.0 + checksum: 7d205599ea3cccc262bad5cc173d3242d6bf8138c99458509230e4ecef07a52d6ddcde5a1dbd49ace655c0af51d2dbadef3748697292ea4d86da19d9e03e19c0 + languageName: node + linkType: hard + "@types/js-levenshtein@npm:^1.1.1": version: 1.1.1 resolution: "@types/js-levenshtein@npm:1.1.1" @@ -7955,13 +8004,13 @@ __metadata: languageName: node linkType: hard -"@types/jscodeshift@npm:^0.11.5": - version: 0.11.5 - resolution: "@types/jscodeshift@npm:0.11.5" +"@types/jscodeshift@npm:^0.11.6": + version: 0.11.6 + resolution: "@types/jscodeshift@npm:0.11.6" dependencies: ast-types: ^0.14.1 recast: ^0.20.3 - checksum: 5929f729477792a2c745289399ac0e2c0c46d4970031fa188073154262c6b0fcb03cf926d70a9fbcdc4c299df0e7fa1f0d6548e6bd1bb03c8245918c5b1a60de + checksum: 418d34488f74e711b37fcfce5129df3494d7fd30e852b3e80ff659ef0b1a4a83911e62883a10d7e1111316b569fa91a5a6a6d22fee86c2d69db829e25b534b27 languageName: node linkType: hard @@ -13390,6 +13439,13 @@ __metadata: languageName: node linkType: hard +"diff-sequences@npm:^29.4.3": + version: 29.4.3 + resolution: "diff-sequences@npm:29.4.3" + checksum: 28b265e04fdddcf7f9f814effe102cc95a9dec0564a579b5aed140edb24fc345c611ca52d76d725a3cab55d3888b915b5e8a4702e0f6058968a90fa5f41fcde7 + languageName: node + linkType: hard + "diff@npm:^4.0.1": version: 4.0.2 resolution: "diff@npm:4.0.2" @@ -14829,6 +14885,19 @@ __metadata: languageName: node linkType: hard +"expect@npm:^29.0.0": + version: 29.5.0 + resolution: "expect@npm:29.5.0" + dependencies: + "@jest/expect-utils": ^29.5.0 + jest-get-type: ^29.4.3 + jest-matcher-utils: ^29.5.0 + jest-message-util: ^29.5.0 + jest-util: ^29.5.0 + checksum: 58f70b38693df6e5c6892db1bcd050f0e518d6f785175dc53917d4fa6a7359a048e5690e19ddcb96b65c4493881dd89a3dabdab1a84dfa55c10cdbdabf37b2d7 + languageName: node + linkType: hard + "expect@npm:^29.3.1": version: 29.3.1 resolution: "expect@npm:29.3.1" @@ -18235,6 +18304,18 @@ fsevents@^1.2.7: languageName: node linkType: hard +"jest-diff@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-diff@npm:29.5.0" + dependencies: + chalk: ^4.0.0 + diff-sequences: ^29.4.3 + jest-get-type: ^29.4.3 + pretty-format: ^29.5.0 + checksum: dfd0f4a299b5d127779c76b40106c37854c89c3e0785098c717d52822d6620d227f6234c3a9291df204d619e799e3654159213bf93220f79c8e92a55475a3d39 + languageName: node + linkType: hard + "jest-docblock@npm:^27.5.1": version: 27.5.1 resolution: "jest-docblock@npm:27.5.1" @@ -18343,6 +18424,13 @@ fsevents@^1.2.7: languageName: node linkType: hard +"jest-get-type@npm:^29.4.3": + version: 29.4.3 + resolution: "jest-get-type@npm:29.4.3" + checksum: 6ac7f2dde1c65e292e4355b6c63b3a4897d7e92cb4c8afcf6d397f2682f8080e094c8b0b68205a74d269882ec06bf696a9de6cd3e1b7333531e5ed7b112605ce + languageName: node + linkType: hard + "jest-haste-map@npm:^26.6.2": version: 26.6.2 resolution: "jest-haste-map@npm:26.6.2" @@ -18484,6 +18572,18 @@ fsevents@^1.2.7: languageName: node linkType: hard +"jest-matcher-utils@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-matcher-utils@npm:29.5.0" + dependencies: + chalk: ^4.0.0 + jest-diff: ^29.5.0 + jest-get-type: ^29.4.3 + pretty-format: ^29.5.0 + checksum: 1d3e8c746e484a58ce194e3aad152eff21fd0896e8b8bf3d4ab1a4e2cbfed95fb143646f4ad9fdf6e42212b9e8fc033268b58e011b044a9929df45485deb5ac9 + languageName: node + linkType: hard + "jest-message-util@npm:^27.5.1": version: 27.5.1 resolution: "jest-message-util@npm:27.5.1" @@ -18535,6 +18635,23 @@ fsevents@^1.2.7: languageName: node linkType: hard +"jest-message-util@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-message-util@npm:29.5.0" + dependencies: + "@babel/code-frame": ^7.12.13 + "@jest/types": ^29.5.0 + "@types/stack-utils": ^2.0.0 + chalk: ^4.0.0 + graceful-fs: ^4.2.9 + micromatch: ^4.0.4 + pretty-format: ^29.5.0 + slash: ^3.0.0 + stack-utils: ^2.0.3 + checksum: daddece6bbf846eb6a2ab9be9f2446e54085bef4e5cecd13d2a538fa9c01cb89d38e564c6b74fd8e12d37ed9eface8a362240ae9f21d68b214590631e7a0d8bf + languageName: node + linkType: hard + "jest-mock@npm:^27.5.1": version: 27.5.1 resolution: "jest-mock@npm:27.5.1" @@ -18836,7 +18953,7 @@ fsevents@^1.2.7: languageName: node linkType: hard -"jest-util@npm:^27.0.0, jest-util@npm:^27.5.1": +"jest-util@npm:^27.5.1": version: 27.5.1 resolution: "jest-util@npm:27.5.1" dependencies: @@ -18878,6 +18995,20 @@ fsevents@^1.2.7: languageName: node linkType: hard +"jest-util@npm:^29.5.0": + version: 29.5.0 + resolution: "jest-util@npm:29.5.0" + dependencies: + "@jest/types": ^29.5.0 + "@types/node": "*" + chalk: ^4.0.0 + ci-info: ^3.2.0 + graceful-fs: ^4.2.9 + picomatch: ^2.2.3 + checksum: fd9212950d34d2ecad8c990dda0d8ea59a8a554b0c188b53ea5d6c4a0829a64f2e1d49e6e85e812014933d17426d7136da4785f9cf76fff1799de51b88bc85d3 + languageName: node + linkType: hard + "jest-validate@npm:^27.5.1": version: 27.5.1 resolution: "jest-validate@npm:27.5.1" @@ -19004,7 +19135,7 @@ fsevents@^1.2.7: languageName: node linkType: hard -"jest@npm:^27, jest@npm:^27.4.3": +"jest@npm:^27.4.3": version: 27.5.1 resolution: "jest@npm:27.5.1" dependencies: @@ -19322,15 +19453,6 @@ fsevents@^1.2.7: languageName: node linkType: hard -"json5@npm:2.x, json5@npm:^2.1.2, json5@npm:^2.2.0, json5@npm:^2.2.1": - version: 2.2.1 - resolution: "json5@npm:2.2.1" - bin: - json5: lib/cli.js - checksum: 74b8a23b102a6f2bf2d224797ae553a75488b5adbaee9c9b6e5ab8b510a2fc6e38f876d4c77dea672d4014a44b2399e15f2051ac2b37b87f74c0c7602003543b - languageName: node - linkType: hard - "json5@npm:^1.0.1": version: 1.0.1 resolution: "json5@npm:1.0.1" @@ -19342,6 +19464,15 @@ fsevents@^1.2.7: languageName: node linkType: hard +"json5@npm:^2.1.2, json5@npm:^2.2.0, json5@npm:^2.2.1": + version: 2.2.1 + resolution: "json5@npm:2.2.1" + bin: + json5: lib/cli.js + checksum: 74b8a23b102a6f2bf2d224797ae553a75488b5adbaee9c9b6e5ab8b510a2fc6e38f876d4c77dea672d4014a44b2399e15f2051ac2b37b87f74c0c7602003543b + languageName: node + linkType: hard + "json5@npm:^2.2.3": version: 2.2.3 resolution: "json5@npm:2.2.3" @@ -23635,6 +23766,17 @@ fsevents@^1.2.7: languageName: node linkType: hard +"pretty-format@npm:^29.0.0, pretty-format@npm:^29.5.0": + version: 29.5.0 + resolution: "pretty-format@npm:29.5.0" + dependencies: + "@jest/schemas": ^29.4.3 + ansi-styles: ^5.0.0 + react-is: ^18.0.0 + checksum: 4065356b558e6db25b4d41a01efb386935a6c06a0c9c104ef5ce59f2f476b8210edb8b3949b386e60ada0a6dc5ebcb2e6ccddc8c64dfd1a9943c3c3a9e7eaf89 + languageName: node + linkType: hard + "pretty-format@npm:^29.3.1": version: 29.3.1 resolution: "pretty-format@npm:29.3.1" @@ -27933,39 +28075,6 @@ fsevents@^1.2.7: languageName: node linkType: hard -"ts-jest@npm:^27": - version: 27.1.5 - resolution: "ts-jest@npm:27.1.5" - dependencies: - bs-logger: 0.x - fast-json-stable-stringify: 2.x - jest-util: ^27.0.0 - json5: 2.x - lodash.memoize: 4.x - make-error: 1.x - semver: 7.x - yargs-parser: 20.x - peerDependencies: - "@babel/core": ">=7.0.0-beta.0 <8" - "@types/jest": ^27.0.0 - babel-jest: ">=27.0.0 <28" - jest: ^27.0.0 - typescript: ">=3.8 <5.0" - peerDependenciesMeta: - "@babel/core": - optional: true - "@types/jest": - optional: true - babel-jest: - optional: true - esbuild: - optional: true - bin: - ts-jest: cli.js - checksum: 3ef51c538b82f49b3f529331c1a017871a2f90e7a9a6e69333304755036d121818c6b120e2ce32dd161ff8bb2487efec0c790753ecd39b46a9ed1ce0d241464c - languageName: node - linkType: hard - "ts-jest@npm:^29": version: 29.0.5 resolution: "ts-jest@npm:29.0.5" @@ -28262,23 +28371,23 @@ fsevents@^1.2.7: languageName: node linkType: hard -"typescript@npm:^4.8.0": - version: 4.8.4 - resolution: "typescript@npm:4.8.4" +"typescript@npm:^4.9": + version: 4.9.5 + resolution: "typescript@npm:4.9.5" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 3e4f061658e0c8f36c820802fa809e0fd812b85687a9a2f5430bc3d0368e37d1c9605c3ce9b39df9a05af2ece67b1d844f9f6ea8ff42819f13bcb80f85629af0 + checksum: ee000bc26848147ad423b581bd250075662a354d84f0e06eb76d3b892328d8d4440b7487b5a83e851b12b255f55d71835b008a66cbf8f255a11e4400159237db languageName: node linkType: hard -"typescript@npm:^4.9": - version: 4.9.5 - resolution: "typescript@npm:4.9.5" +"typescript@npm:^5": + version: 5.1.3 + resolution: "typescript@npm:5.1.3" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: ee000bc26848147ad423b581bd250075662a354d84f0e06eb76d3b892328d8d4440b7487b5a83e851b12b255f55d71835b008a66cbf8f255a11e4400159237db + checksum: d9d51862d98efa46534f2800a1071a613751b1585dc78884807d0c179bcd93d6e9d4012a508e276742f5f33c480adefc52ffcafaf9e0e00ab641a14cde9a31c7 languageName: node linkType: hard @@ -28332,23 +28441,23 @@ fsevents@^1.2.7: languageName: node linkType: hard -"typescript@patch:typescript@^4.8.0#~builtin": - version: 4.8.4 - resolution: "typescript@patch:typescript@npm%3A4.8.4#~builtin::version=4.8.4&hash=701156" +"typescript@patch:typescript@^4.9#~builtin": + version: 4.9.5 + resolution: "typescript@patch:typescript@npm%3A4.9.5#~builtin::version=4.9.5&hash=701156" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 301459fc3eb3b1a38fe91bf96d98eb55da88a9cb17b4ef80b4d105d620f4d547ba776cc27b44cc2ef58b66eda23fe0a74142feb5e79a6fb99f54fc018a696afa + checksum: 2eee5c37cad4390385db5db5a8e81470e42e8f1401b0358d7390095d6f681b410f2c4a0c496c6ff9ebd775423c7785cdace7bcdad76c7bee283df3d9718c0f20 languageName: node linkType: hard -"typescript@patch:typescript@^4.9#~builtin": - version: 4.9.5 - resolution: "typescript@patch:typescript@npm%3A4.9.5#~builtin::version=4.9.5&hash=701156" +"typescript@patch:typescript@^5#~builtin": + version: 5.1.3 + resolution: "typescript@patch:typescript@npm%3A5.1.3#~builtin::version=5.1.3&hash=701156" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 2eee5c37cad4390385db5db5a8e81470e42e8f1401b0358d7390095d6f681b410f2c4a0c496c6ff9ebd775423c7785cdace7bcdad76c7bee283df3d9718c0f20 + checksum: 32a25b2e128a4616f999d4ee502aabb1525d5647bc8955e6edf05d7fbc53af8aa98252e2f6ba80bcedfc0260c982b885f3c09cfac8bb65d2924f3133ad1e1e62 languageName: node linkType: hard @@ -30364,7 +30473,7 @@ fsevents@^1.2.7: languageName: node linkType: hard -"yargs-parser@npm:20.2.9, yargs-parser@npm:20.x, yargs-parser@npm:^20.2.2": +"yargs-parser@npm:20.2.9, yargs-parser@npm:^20.2.2": version: 20.2.9 resolution: "yargs-parser@npm:20.2.9" checksum: 8bb69015f2b0ff9e17b2c8e6bfe224ab463dd00ca211eece72a4cd8a906224d2703fb8a326d36fdd0e68701e201b2a60ed7cf81ce0fd9b3799f9fe7745977ae3 From 16ab2b8f183f3f7f785425225d7584406d47c379 Mon Sep 17 00:00:00 2001 From: Ben Durrant Date: Fri, 2 Jun 2023 01:13:51 +0100 Subject: [PATCH 06/24] add codemod --- packages/rtk-codemods/package.json | 1 + .../transforms/enhanceEndpoint/README.md | 28 +++++ .../__testfixtures__/basic.input.js | 38 +++++++ .../__testfixtures__/basic.output.js | 22 ++++ .../transforms/enhanceEndpoint/index.ts | 105 ++++++++++++++++++ .../transforms/enhanceEndpoint/test.js | 9 ++ yarn.lock | 1 + 7 files changed, 204 insertions(+) create mode 100644 packages/rtk-codemods/transforms/enhanceEndpoint/README.md create mode 100644 packages/rtk-codemods/transforms/enhanceEndpoint/__testfixtures__/basic.input.js create mode 100644 packages/rtk-codemods/transforms/enhanceEndpoint/__testfixtures__/basic.output.js create mode 100644 packages/rtk-codemods/transforms/enhanceEndpoint/index.ts create mode 100644 packages/rtk-codemods/transforms/enhanceEndpoint/test.js diff --git a/packages/rtk-codemods/package.json b/packages/rtk-codemods/package.json index d6e189b8ee..80d69e4b8b 100644 --- a/packages/rtk-codemods/package.json +++ b/packages/rtk-codemods/package.json @@ -25,6 +25,7 @@ "@types/jest": "^29", "@types/jscodeshift": "^0.11.6", "codemod-cli": "^3.2.0", + "jscodeshift": "^0.15.0", "ts-node": "^10.4.0", "typescript": "^5" }, diff --git a/packages/rtk-codemods/transforms/enhanceEndpoint/README.md b/packages/rtk-codemods/transforms/enhanceEndpoint/README.md new file mode 100644 index 0000000000..88fa328a02 --- /dev/null +++ b/packages/rtk-codemods/transforms/enhanceEndpoint/README.md @@ -0,0 +1,28 @@ +# enhanceEndpoint + +Transforms enhanceEndpoints calls into addTagType and enhanceEndpoint calls, in preparation for RTK 2.0. + +## Usage + +``` +npx @reduxjs/rtk-codemods enhanceEndpoint path/of/files/ or/some**/*glob.js + +# or + +yarn global add @reduxjs/rtk-codemods +@reduxjs/rtk-codemods enhanceEndpoint path/of/files/ or/some**/*glob.js +``` + +## Local Usage + +``` +node ./bin/cli.js enhanceEndpoint path/of/files/ or/some**/*glob.js +``` + +## Input / Output + + + + + + diff --git a/packages/rtk-codemods/transforms/enhanceEndpoint/__testfixtures__/basic.input.js b/packages/rtk-codemods/transforms/enhanceEndpoint/__testfixtures__/basic.input.js new file mode 100644 index 0000000000..4972286137 --- /dev/null +++ b/packages/rtk-codemods/transforms/enhanceEndpoint/__testfixtures__/basic.input.js @@ -0,0 +1,38 @@ +const withTags = api.enhanceEndpoints({ + addTagTypes: ['tag1'] +}); + +const mutation2 = 'mutation2'; + +const withPartials = withTags.enhanceEndpoints({ + endpoints: { + query1: { + providesTags: ['tag1'] + }, + mutation1(definition) { + definition.invalidatesTags = ['tag1'] + }, + [mutation2]: (definition) => {} + } +}) + +const tags = ['tag1'] + +const withBoth = api.enhanceEndpoints({ + addTagTypes: tags, + endpoints: { + ["query1"]: { + providesTags: ['tag1'] + }, + } +}) + +const addTagTypes = tags + +const chained = api + .enhanceEndpoints({ + addTagTypes + }) + .injectEndpoints({ + endpoints: () => {} + }) \ No newline at end of file diff --git a/packages/rtk-codemods/transforms/enhanceEndpoint/__testfixtures__/basic.output.js b/packages/rtk-codemods/transforms/enhanceEndpoint/__testfixtures__/basic.output.js new file mode 100644 index 0000000000..a23264b143 --- /dev/null +++ b/packages/rtk-codemods/transforms/enhanceEndpoint/__testfixtures__/basic.output.js @@ -0,0 +1,22 @@ +const withTags = api.addTagTypes('tag1'); + +const mutation2 = 'mutation2'; + +const withPartials = withTags.enhanceEndpoint("query1", { + providesTags: ['tag1'] +}).enhanceEndpoint("mutation1", (definition) => { + definition.invalidatesTags = ['tag1'] +}).enhanceEndpoint(mutation2, (definition) => {}) + +const tags = ['tag1'] + +const withBoth = api.addTagTypes(...tags).enhanceEndpoint("query1", { + providesTags: ['tag1'] +}) + +const addTagTypes = tags + +const chained = api.addTagTypes(...addTagTypes) + .injectEndpoints({ + endpoints: () => {} + }) \ No newline at end of file diff --git a/packages/rtk-codemods/transforms/enhanceEndpoint/index.ts b/packages/rtk-codemods/transforms/enhanceEndpoint/index.ts new file mode 100644 index 0000000000..3be152d660 --- /dev/null +++ b/packages/rtk-codemods/transforms/enhanceEndpoint/index.ts @@ -0,0 +1,105 @@ +import type { + Transform, + MemberExpression, + ObjectExpression, + RestElement, + JSCodeshift, +} from 'jscodeshift'; + +type Prop = Extract['value']; + +const createAddTagTypesCall = ( + j: JSCodeshift, + object: MemberExpression['object'], + addTagTypes: Prop +) => { + const newCall = j.callExpression(j.memberExpression(object, j.identifier('addTagTypes')), []); + if (addTagTypes.type === 'Identifier') { + newCall.arguments.push(j.spreadElement(addTagTypes)); + } else if (addTagTypes.type === 'ArrayExpression') { + newCall.arguments = addTagTypes.elements.filter( + (el): el is Exclude => !!(el && el.type !== 'RestElement') + ); + } + return newCall; +}; + +const transform: Transform = (file, api) => { + const j = api.jscodeshift; + + const root = j(file.source); + + return root + .find(j.CallExpression, { + callee: { + property: { + name: 'enhanceEndpoints', + }, + }, + }) + .forEach((path) => { + const callee = path.value.callee as MemberExpression; + const [config] = path.value.arguments; + if (config.type === 'ObjectExpression') { + let addTagTypes: Prop | undefined = undefined; + let endpoints: Prop | undefined = undefined; + for (const property of config.properties) { + if ( + (property.type === 'ObjectProperty' || property.type === 'Property') && + property.key.type === 'Identifier' + ) { + switch (property.key.name) { + case 'addTagTypes': + addTagTypes = property.value; + break; + case 'endpoints': + endpoints = property.value; + break; + } + } + } + if (!endpoints) { + if (!addTagTypes) { + return; + } + // no endpoints - we can go ahead and replace + path.replace(createAddTagTypesCall(j, callee.object, addTagTypes)); + } else { + let calleeObject = addTagTypes + ? createAddTagTypesCall(j, callee.object, addTagTypes) + : callee.object; + if (endpoints.type === 'ObjectExpression') { + for (const endpointProp of endpoints.properties) { + if (endpointProp.type === 'ObjectProperty') { + const endpointName = + endpointProp.key.type === 'Identifier' && !endpointProp.computed + ? j.stringLiteral(endpointProp.key.name) + : endpointProp.key; + calleeObject = j.callExpression( + j.memberExpression(calleeObject, j.identifier('enhanceEndpoint')), + [endpointName, endpointProp.value as any] + ); + } else if (endpointProp.type === 'ObjectMethod') { + const endpointName = + endpointProp.key.type === 'Identifier' + ? j.stringLiteral(endpointProp.key.name) + : endpointProp.key; + calleeObject = j.callExpression( + j.memberExpression(calleeObject, j.identifier('enhanceEndpoint')), + [endpointName, j.arrowFunctionExpression(endpointProp.params, endpointProp.body)] + ); + } + } + } + path.replace(calleeObject); + } + } + }) + .toSource({ + arrowParensAlways: true, + }); +}; + +export const parser = 'tsx'; + +export default transform; diff --git a/packages/rtk-codemods/transforms/enhanceEndpoint/test.js b/packages/rtk-codemods/transforms/enhanceEndpoint/test.js new file mode 100644 index 0000000000..2fa121219b --- /dev/null +++ b/packages/rtk-codemods/transforms/enhanceEndpoint/test.js @@ -0,0 +1,9 @@ +'use strict'; + +const { runTransformTest } = require('codemod-cli'); + +runTransformTest({ + name: 'enhanceEndpoint', + path: require.resolve('./index.ts'), + fixtureDir: `${__dirname}/__testfixtures__/`, +}); diff --git a/yarn.lock b/yarn.lock index 61c8567935..0560b9ca1a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6728,6 +6728,7 @@ __metadata: eslint-plugin-node: ^11.1.0 eslint-plugin-prettier: ^3.4.0 jest: ^29 + jscodeshift: ^0.15.0 prettier: ^2.2.1 ts-jest: ^29 ts-node: ^10.4.0 From 36187be4ecbb585b28275c355fbbf6f867429770 Mon Sep 17 00:00:00 2001 From: Ben Durrant Date: Fri, 2 Jun 2023 01:46:38 +0100 Subject: [PATCH 07/24] fix APIProvider --- packages/toolkit/src/query/react/ApiProvider.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/toolkit/src/query/react/ApiProvider.tsx b/packages/toolkit/src/query/react/ApiProvider.tsx index abaef8c2cc..c3aed581a1 100644 --- a/packages/toolkit/src/query/react/ApiProvider.tsx +++ b/packages/toolkit/src/query/react/ApiProvider.tsx @@ -5,7 +5,7 @@ import React from 'react' import type { ReactReduxContextValue } from 'react-redux' import { Provider } from 'react-redux' import { setupListeners } from '@reduxjs/toolkit/query' -import type { Api } from '@reduxjs/toolkit/dist/query/apiTypes' +import type { Api, BaseApiMethods } from '@reduxjs/toolkit/dist/query/apiTypes' /** * Can be used as a `Provider` if you **do not already have a Redux store**. @@ -31,9 +31,9 @@ import type { Api } from '@reduxjs/toolkit/dist/query/apiTypes' * conflict with each other - please use the traditional redux setup * in that case. */ -export function ApiProvider>(props: { +export function ApiProvider(props: { children: any - api: A + api: Omit, keyof BaseApiMethods> setupListeners?: Parameters[1] | false context?: Context }) { From 12d87202f5f6544158eb3348a91b6904f7f906d9 Mon Sep 17 00:00:00 2001 From: Ben Durrant Date: Sun, 4 Jun 2023 21:31:52 +0100 Subject: [PATCH 08/24] simplify typing using ApiModules instead of Omit --- packages/toolkit/src/query/core/buildInitiate.ts | 9 +++------ .../toolkit/src/query/core/buildMiddleware/types.ts | 8 +++----- packages/toolkit/src/query/react/ApiProvider.tsx | 5 +++-- packages/toolkit/src/query/react/buildHooks.ts | 12 +++--------- 4 files changed, 12 insertions(+), 22 deletions(-) diff --git a/packages/toolkit/src/query/core/buildInitiate.ts b/packages/toolkit/src/query/core/buildInitiate.ts index dae9c013d8..1109dadd63 100644 --- a/packages/toolkit/src/query/core/buildInitiate.ts +++ b/packages/toolkit/src/query/core/buildInitiate.ts @@ -14,8 +14,8 @@ import type { } from '@reduxjs/toolkit' import type { SubscriptionOptions, RootState } from './apiState' import type { InternalSerializeQueryArgs } from '../defaultSerializeQueryArgs' -import type { Api, ApiContext, BaseApiMethods } from '../apiTypes' -import type { ApiEndpointQuery } from './module' +import type { ApiContext, ApiModules } from '../apiTypes' +import type { ApiEndpointQuery, CoreModule } from './module' import type { BaseQueryError, QueryReturnValue } from '../baseQueryTypes' import type { QueryResultSelectorResult } from './buildSelectors' import type { Dispatch } from 'redux' @@ -197,10 +197,7 @@ export function buildInitiate({ serializeQueryArgs: InternalSerializeQueryArgs queryThunk: QueryThunk mutationThunk: MutationThunk - api: Omit< - Api, - keyof BaseApiMethods - > + api: ApiModules[CoreModule] context: ApiContext }) { const runningQueries: Map< diff --git a/packages/toolkit/src/query/core/buildMiddleware/types.ts b/packages/toolkit/src/query/core/buildMiddleware/types.ts index 6c24d38011..e057d18d08 100644 --- a/packages/toolkit/src/query/core/buildMiddleware/types.ts +++ b/packages/toolkit/src/query/core/buildMiddleware/types.ts @@ -7,7 +7,7 @@ import type { UnknownAction, } from '@reduxjs/toolkit' -import type { Api, ApiContext, BaseApiMethods } from '../../apiTypes' +import type { ApiContext, ApiModules } from '../../apiTypes' import type { AssertTagTypes, EndpointDefinitions, @@ -24,6 +24,7 @@ import type { QueryThunkArg, ThunkResult, } from '../buildThunks' +import type { CoreModule } from '../module' export type QueryStateMeta = Record export type TimeoutId = ReturnType @@ -41,10 +42,7 @@ export interface BuildMiddlewareInput< context: ApiContext queryThunk: QueryThunk mutationThunk: MutationThunk - api: Omit< - Api, - keyof BaseApiMethods - > + api: ApiModules[CoreModule] assertTagType: AssertTagTypes } diff --git a/packages/toolkit/src/query/react/ApiProvider.tsx b/packages/toolkit/src/query/react/ApiProvider.tsx index c3aed581a1..f82dcc1b6e 100644 --- a/packages/toolkit/src/query/react/ApiProvider.tsx +++ b/packages/toolkit/src/query/react/ApiProvider.tsx @@ -4,8 +4,9 @@ import { useEffect } from 'react' import React from 'react' import type { ReactReduxContextValue } from 'react-redux' import { Provider } from 'react-redux' +import type { ApiModules } from '@reduxjs/toolkit/query' import { setupListeners } from '@reduxjs/toolkit/query' -import type { Api, BaseApiMethods } from '@reduxjs/toolkit/dist/query/apiTypes' +import type { CoreModule } from '../core/module' /** * Can be used as a `Provider` if you **do not already have a Redux store**. @@ -33,7 +34,7 @@ import type { Api, BaseApiMethods } from '@reduxjs/toolkit/dist/query/apiTypes' */ export function ApiProvider(props: { children: any - api: Omit, keyof BaseApiMethods> + api: ApiModules[CoreModule] setupListeners?: Parameters[1] | false context?: Context }) { diff --git a/packages/toolkit/src/query/react/buildHooks.ts b/packages/toolkit/src/query/react/buildHooks.ts index 3f4530eca5..132f6d1e03 100644 --- a/packages/toolkit/src/query/react/buildHooks.ts +++ b/packages/toolkit/src/query/react/buildHooks.ts @@ -15,6 +15,7 @@ import { useRef, useState, } from 'react' +import type { ApiModules } from '@reduxjs/toolkit/query' import { QueryStatus, skipToken } from '@reduxjs/toolkit/query' import type { QuerySubState, @@ -40,11 +41,7 @@ import type { } from '@reduxjs/toolkit/dist/query/core/buildInitiate' import type { SerializeQueryArgs } from '@reduxjs/toolkit/dist/query/defaultSerializeQueryArgs' import { shallowEqual } from 'react-redux' -import type { - Api, - ApiContext, - BaseApiMethods, -} from '@reduxjs/toolkit/dist/query/apiTypes' +import type { ApiContext } from '@reduxjs/toolkit/dist/query/apiTypes' import type { Id, NoInfer, @@ -595,10 +592,7 @@ export function buildHooks({ serializeQueryArgs, context, }: { - api: Omit< - Api, - keyof BaseApiMethods - > + api: ApiModules[CoreModule] moduleOptions: Required serializeQueryArgs: SerializeQueryArgs context: ApiContext From 81f187e517c2fe8ce4542fcec6f443b7fa8aad1d Mon Sep 17 00:00:00 2001 From: Ben Durrant Date: Sun, 4 Jun 2023 21:41:26 +0100 Subject: [PATCH 09/24] fix apiprovider type --- packages/toolkit/src/query/react/ApiProvider.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/toolkit/src/query/react/ApiProvider.tsx b/packages/toolkit/src/query/react/ApiProvider.tsx index f82dcc1b6e..df3b115433 100644 --- a/packages/toolkit/src/query/react/ApiProvider.tsx +++ b/packages/toolkit/src/query/react/ApiProvider.tsx @@ -34,7 +34,7 @@ import type { CoreModule } from '../core/module' */ export function ApiProvider(props: { children: any - api: ApiModules[CoreModule] + api: ApiModules[CoreModule] setupListeners?: Parameters[1] | false context?: Context }) { From b65f6b5d271d137592c2ce076f0303cc638722d2 Mon Sep 17 00:00:00 2001 From: Ben Durrant Date: Sun, 4 Jun 2023 22:53:03 +0100 Subject: [PATCH 10/24] update docs and remove enhanceEndpoints from typing (runtime fallback still exists) --- .../api/created-api/code-splitting.mdx | 64 +++++++++++-------- docs/rtk-query/api/created-api/overview.mdx | 10 ++- docs/rtk-query/usage/code-generation.mdx | 2 +- .../kitchen-sink/src/app/services/api.ts | 8 +-- packages/toolkit/src/query/apiTypes.ts | 31 +-------- packages/toolkit/src/query/createApi.ts | 35 ++++++---- 6 files changed, 72 insertions(+), 78 deletions(-) diff --git a/docs/rtk-query/api/created-api/code-splitting.mdx b/docs/rtk-query/api/created-api/code-splitting.mdx index 31d76e3551..1c0ffe5f8c 100644 --- a/docs/rtk-query/api/created-api/code-splitting.mdx +++ b/docs/rtk-query/api/created-api/code-splitting.mdx @@ -13,7 +13,7 @@ Each API slice allows [additional endpoint definitions to be injected at runtime The individual API slice endpoint definitions can also be split across multiple files. This is primarily useful for working with API slices that were [code-generated from an API schema file](../../usage/code-generation.mdx), allowing you to add additional custom behavior and configuration to a set of automatically-generated endpoint definitions. -Each API slice object has `injectEndpoints` and `enhanceEndpoints` functions to support these use cases. +Each API slice object has `injectEndpoints`, `addTagTypes` and `enhanceEndpoint` functions to support these use cases. ## `injectEndpoints` @@ -39,29 +39,44 @@ Endpoints will not be overridden unless `overrideExisting` is set to `true`. If This method is primarily useful for code splitting and hot reloading. -## `enhanceEndpoints` +## `addTagTypes` #### Signature ```ts no-transpile -const enhanceEndpoints = (endpointOptions: EnhanceEndpointsOptions) => - EnhancedApiSlice +const addTagTypes = (...newTags: readonly string[]) => EnhancedApiSlice +``` -interface EnhanceEndpointsOptions { - addTagTypes?: readonly string[] - endpoints?: Record> -} +#### Description + +Accepts a number of new tags to add to the API slice. + +Returns an updated and enhanced version of the API slice object, with the new tags added. + +This is primarily useful for chaining before `injectEndpoints` or `enhanceEndpoint`, to add tags which can then be used by new/enhanced endpoints. + +## `enhanceEndpoint` + +#### Signature + +```ts no-transpile +const enhanceEndpoint = ( + endpointName: string, + partialDefinition: + | Partial + | ((definition: EndpointDefinition) => void) +) => EnhancedApiSlice ``` #### Description -Any provided tag types or endpoint definitions will be merged into the existing endpoint definitions for this API slice. Unlike `injectEndpoints`, the partial endpoint definitions will not _replace_ existing definitions, but are rather merged together on a per-definition basis (ie, `Object.assign(existingEndpoint, newPartialEndpoint)`). +Provided partial definition will be merged into the existing endpoint definition for this API slice. Unlike `injectEndpoints`, the partial endpoint definition will not _replace_ the existing definition, but is rather merged together (i.e. `Object.assign(existingEndpoint, newPartialEndpoint)`). Returns an updated and enhanced version of the API slice object, containing the combined endpoint definitions. This is primarily useful for taking an API slice object that was code-generated from an API schema file like OpenAPI, and adding additional specific hand-written configuration for cache invalidation management on top of the generated endpoint definitions. -For example, `enhanceEndpoints` can be used to modify caching behavior by changing the values of `providesTags`, `invalidatesTags`, and `keepUnusedDataFor`: +For example, `enhanceEndpoint` can be used to modify caching behavior by changing the values of `providesTags`, `invalidatesTags`, and `keepUnusedDataFor`: ```ts // file: api.ts noEmit @@ -91,20 +106,17 @@ export const api = createApi({ // file: enhanceEndpoints.ts import { api } from './api' -const enhancedApi = api.enhanceEndpoints({ - addTagTypes: ['User'], - endpoints: { - getUserByUserId: { - providesTags: ['User'], - }, - patchUserByUserId: { - invalidatesTags: ['User'], - }, - // alternatively, define a function which is called with the endpoint definition as an argument - getUsers(endpoint) { - endpoint.providesTags = ['User'] - endpoint.keepUnusedDataFor = 120 - }, - }, -}) +const enhancedApi = api + .addTagTypes('User') + .enhanceEndpoint('getUserByUserId', { + providesTags: ['User'], + }) + .enhanceEndpoint('patchUserByUserId', { + invalidatesTags: ['User'], + }) + // alternatively, define a function which is called with the endpoint definition as an argument + .enhanceEndpoint('getUsers', (endpoint) => { + endpoint.providesTags = ['User'] + endpoint.keepUnusedDataFor = 120 + }) ``` diff --git a/docs/rtk-query/api/created-api/overview.mdx b/docs/rtk-query/api/created-api/overview.mdx index c64dd64b72..a4ec182bf8 100644 --- a/docs/rtk-query/api/created-api/overview.mdx +++ b/docs/rtk-query/api/created-api/overview.mdx @@ -42,7 +42,13 @@ type Api = { // Code splitting and generation injectEndpoints: (options: InjectEndpointsOptions) => UpdatedApi - enhanceEndpoints: (options: EnhanceEndpointsOptions) => UpdatedApi + addTagTypes: (...newTags: readonly string[]) => UpdatedApi + enhanceEndpoint: ( + endpointName: string, + partialDefinition: + | Partial + | ((definition: EndpointDefinition) => void) + ) => UpdatedApi // Utilities utils: { @@ -114,7 +120,7 @@ Each API slice allows [additional endpoint definitions to be injected at runtime The individual API slice endpoint definitions can also be split across multiple files. This is primarily useful for working with API slices that were [code-generated from an API schema file](../../usage/code-generation.mdx), allowing you to add additional custom behavior and configuration to a set of automatically-generated endpoint definitions. -Each API slice object has `injectEndpoints` and `enhanceEndpoints` functions to support these use cases. +Each API slice object has `injectEndpoints`, `addTagTypes` and `enhanceEndpoint` functions to support these use cases. :::info API Reference diff --git a/docs/rtk-query/usage/code-generation.mdx b/docs/rtk-query/usage/code-generation.mdx index efd4551e05..774d3c5c00 100644 --- a/docs/rtk-query/usage/code-generation.mdx +++ b/docs/rtk-query/usage/code-generation.mdx @@ -69,7 +69,7 @@ That will result in all generated endpoints having `providesTags`/`invalidatesTa Note that this will only result in string tags with no ids, so it might lead to scenarios where too much is invalidated and unneccessary requests are made on mutation. -In that case it is still recommended to manually specify tags by using [`enhanceEndpoints`](../api/created-api/code-splitting.mdx) on top of the generated api and manually declare `providesTags`/`invalidatesTags`. +In that case it is still recommended to manually specify tags by using [`addTagTypes` and `enhanceEndpoint`](../api/created-api/code-splitting.mdx) on top of the generated api and manually declare `providesTags`/`invalidatesTags`. ### Programmatic usage diff --git a/examples/query/react/kitchen-sink/src/app/services/api.ts b/examples/query/react/kitchen-sink/src/app/services/api.ts index e9c9ab0c56..e042f3a51a 100644 --- a/examples/query/react/kitchen-sink/src/app/services/api.ts +++ b/examples/query/react/kitchen-sink/src/app/services/api.ts @@ -20,7 +20,7 @@ const baseQueryWithRetry = retry(baseQuery, { maxRetries: 6 }) * Create a base API to inject endpoints into elsewhere. * Components using this API should import from the injected site, * in order to get the appropriate types, - * and to ensure that the file injecting the endpoints is loaded + * and to ensure that the file injecting the endpoints is loaded */ export const api = createApi({ /** @@ -47,9 +47,3 @@ export const api = createApi({ */ endpoints: () => ({}), }) - -export const enhancedApi = api.enhanceEndpoints({ - endpoints: () => ({ - getPost: () => 'test', - }), -}) diff --git a/packages/toolkit/src/query/apiTypes.ts b/packages/toolkit/src/query/apiTypes.ts index 9cf8dd2522..e9f75cc7cf 100644 --- a/packages/toolkit/src/query/apiTypes.ts +++ b/packages/toolkit/src/query/apiTypes.ts @@ -96,34 +96,7 @@ export type BaseApiMethods< Enhancers > /** - * A function to enhance a generated API with additional information. Useful with code-generation. - * @deprecated use addTagTypes and/or enhanceEndpoint instead - */ - enhanceEndpoints< - NewTagTypes extends string = never, - NewDefinitions extends EndpointDefinitions = never - >(_: { - addTagTypes?: readonly NewTagTypes[] - endpoints?: UpdateDefinitions< - Definitions, - TagTypes | NoInfer, - NewDefinitions - > extends infer NewDefinitions - ? { - [K in keyof NewDefinitions]?: - | Partial - | ((definition: NewDefinitions[K]) => void) - } - : never - }): Api< - BaseQuery, - UpdateDefinitions, - ReducerPath, - TagTypes | NewTagTypes, - Enhancers - > - /** - *A function to enhance a generated API with additional information. Useful with code-generation. + *A function to add tag types to a generated API. Useful with code-generation. */ addTagTypes( ...addTagTypes: readonly NewTagTypes[] @@ -136,7 +109,7 @@ export type BaseApiMethods< > /** - *A function to enhance a generated API with additional information. Useful with code-generation. + *A function to enhance a generated API endpoint with additional information. Useful with code-generation. */ enhanceEndpoint< QueryName extends QueryKeys, diff --git a/packages/toolkit/src/query/createApi.ts b/packages/toolkit/src/query/createApi.ts index 83966fed0b..89f21b6536 100644 --- a/packages/toolkit/src/query/createApi.ts +++ b/packages/toolkit/src/query/createApi.ts @@ -319,21 +319,30 @@ export function buildCreateApi, ...Module[]]>( } return api }, - enhanceEndpoints({ addTagTypes, endpoints }) { - if (addTagTypes) { - api.addTagTypes(...addTagTypes) - } - if (endpoints) { - for (const [endpointName, partialDefinition] of Object.entries( - endpoints - )) { - ;(api.enhanceEndpoint as any)(endpointName, partialDefinition) - } - } - return api - }, } as Api + // add fallback for runtime - undocumented in TS + // @ts-ignore + api.enhanceEndpoints = ({ + addTagTypes, + endpoints, + }: { + addTagTypes?: string[] + endpoints?: Record + }) => { + if (addTagTypes) { + api.addTagTypes(...addTagTypes) + } + if (endpoints) { + for (const [endpointName, partialDefinition] of Object.entries( + endpoints + )) { + ;(api.enhanceEndpoint as any)(endpointName, partialDefinition) + } + } + return api + } + const initializedModules = modules.map((m) => m.init(api as any, optionsWithDefaults as any, context) ) From 8c38f92b4525311a81fc4f3221e51166bae33d8b Mon Sep 17 00:00:00 2001 From: "ben.durrant" Date: Tue, 6 Jun 2023 19:25:04 +0100 Subject: [PATCH 11/24] use promiseWithResolvers for RTKQ lifecycle management --- .../core/buildMiddleware/cacheLifecycle.ts | 29 ++++---- .../core/buildMiddleware/queryLifecycle.ts | 32 ++++----- .../src/query/core/buildMiddleware/types.ts | 47 ------------- .../src/query/utils/promiseWithResolvers.ts | 67 +++++++++++++++++++ 4 files changed, 100 insertions(+), 75 deletions(-) create mode 100644 packages/toolkit/src/query/utils/promiseWithResolvers.ts diff --git a/packages/toolkit/src/query/core/buildMiddleware/cacheLifecycle.ts b/packages/toolkit/src/query/core/buildMiddleware/cacheLifecycle.ts index d83a25b15f..2f5ea7811b 100644 --- a/packages/toolkit/src/query/core/buildMiddleware/cacheLifecycle.ts +++ b/packages/toolkit/src/query/core/buildMiddleware/cacheLifecycle.ts @@ -13,9 +13,10 @@ import type { PatchCollection, Recipe } from '../buildThunks' import type { ApiMiddlewareInternalHandler, InternalHandlerBuilder, - PromiseWithKnownReason, SubMiddlewareApi, } from './types' +import type { PromiseWithKnownReason } from '../../utils/promiseWithResolvers' +import { promiseWithResolvers } from '../../utils/promiseWithResolvers' export type ReferenceCacheLifecycle = never @@ -274,20 +275,22 @@ export const buildCacheLifecycleHandler: InternalHandlerBuilder = ({ let lifecycle = {} as CacheLifecycle - const cacheEntryRemoved = new Promise((resolve) => { - lifecycle.cacheEntryRemoved = resolve - }) - const cacheDataLoaded: PromiseWithKnownReason< + let cacheEntryRemoved: Promise + ;({ promise: cacheEntryRemoved, resolve: lifecycle.cacheEntryRemoved } = + promiseWithResolvers()) + + const { + promise: cacheDataLoaded, + resolve, + reject, + } = promiseWithResolvers< { data: unknown; meta: unknown }, typeof neverResolvedError - > = Promise.race([ - new Promise<{ data: unknown; meta: unknown }>((resolve) => { - lifecycle.valueResolved = resolve - }), - cacheEntryRemoved.then(() => { - throw neverResolvedError - }), - ]) + >() + lifecycle.valueResolved = resolve + + cacheEntryRemoved.then(() => reject(neverResolvedError), reject) + // prevent uncaught promise rejections from happening. // if the original promise is used in any way, that will create a new promise that will throw again cacheDataLoaded.catch(() => {}) diff --git a/packages/toolkit/src/query/core/buildMiddleware/queryLifecycle.ts b/packages/toolkit/src/query/core/buildMiddleware/queryLifecycle.ts index 0df42c159e..2a2a6740a9 100644 --- a/packages/toolkit/src/query/core/buildMiddleware/queryLifecycle.ts +++ b/packages/toolkit/src/query/core/buildMiddleware/queryLifecycle.ts @@ -8,11 +8,14 @@ import { DefinitionType } from '../../endpointDefinitions' import type { QueryFulfilledRejectionReason } from '../../endpointDefinitions' import type { Recipe } from '../buildThunks' import type { - PromiseWithKnownReason, - PromiseConstructorWithKnownReason, InternalHandlerBuilder, ApiMiddlewareInternalHandler, } from './types' +import type { + PromiseWithKnownReason, + PromiseWithResolvers, +} from '../../utils/promiseWithResolvers' +import { promiseWithResolvers } from '../../utils/promiseWithResolvers' export type ReferenceQueryLifecycle = never @@ -211,10 +214,14 @@ export const buildQueryLifecycleHandler: InternalHandlerBuilder = ({ const isRejectedThunk = isRejected(queryThunk, mutationThunk) const isFullfilledThunk = isFulfilled(queryThunk, mutationThunk) - type CacheLifecycle = { - resolve(value: { data: unknown; meta: unknown }): unknown - reject(value: QueryFulfilledRejectionReason): unknown - } + type CacheLifecycle = Omit< + PromiseWithResolvers< + { data: unknown; meta: unknown }, + QueryFulfilledRejectionReason + >, + 'promise' + > + const lifecycleMap: Record = {} const handler: ApiMiddlewareInternalHandler = (action, mwApi) => { @@ -226,15 +233,10 @@ export const buildQueryLifecycleHandler: InternalHandlerBuilder = ({ const endpointDefinition = context.endpointDefinitions[endpointName] const onQueryStarted = endpointDefinition?.onQueryStarted if (onQueryStarted) { - const lifecycle = {} as CacheLifecycle - const queryFulfilled = - new (Promise as PromiseConstructorWithKnownReason)< - { data: unknown; meta: unknown }, - QueryFulfilledRejectionReason - >((resolve, reject) => { - lifecycle.resolve = resolve - lifecycle.reject = reject - }) + const { promise: queryFulfilled, ...lifecycle } = promiseWithResolvers< + { data: unknown; meta: unknown }, + QueryFulfilledRejectionReason + >() // prevent uncaught promise rejections from happening. // if the original promise is used in any way, that will create a new promise that will throw again queryFulfilled.catch(() => {}) diff --git a/packages/toolkit/src/query/core/buildMiddleware/types.ts b/packages/toolkit/src/query/core/buildMiddleware/types.ts index e057d18d08..1e96000cf7 100644 --- a/packages/toolkit/src/query/core/buildMiddleware/types.ts +++ b/packages/toolkit/src/query/core/buildMiddleware/types.ts @@ -83,50 +83,3 @@ export type ApiMiddlewareInternalHandler = ( export type InternalHandlerBuilder = ( input: BuildSubMiddlewareInput ) => ApiMiddlewareInternalHandler - -export interface PromiseConstructorWithKnownReason { - /** - * Creates a new Promise with a known rejection reason. - * @param executor A callback used to initialize the promise. This callback is passed two arguments: - * a resolve callback used to resolve the promise with a value or the result of another promise, - * and a reject callback used to reject the promise with a provided reason or error. - */ - new ( - executor: ( - resolve: (value: T | PromiseLike) => void, - reject: (reason?: R) => void - ) => void - ): PromiseWithKnownReason -} - -export interface PromiseWithKnownReason - extends Omit, 'then' | 'catch'> { - /** - * Attaches callbacks for the resolution and/or rejection of the Promise. - * @param onfulfilled The callback to execute when the Promise is resolved. - * @param onrejected The callback to execute when the Promise is rejected. - * @returns A Promise for the completion of which ever callback is executed. - */ - then( - onfulfilled?: - | ((value: T) => TResult1 | PromiseLike) - | undefined - | null, - onrejected?: - | ((reason: R) => TResult2 | PromiseLike) - | undefined - | null - ): Promise - - /** - * Attaches a callback for only the rejection of the Promise. - * @param onrejected The callback to execute when the Promise is rejected. - * @returns A Promise for the completion of the callback. - */ - catch( - onrejected?: - | ((reason: R) => TResult | PromiseLike) - | undefined - | null - ): Promise -} diff --git a/packages/toolkit/src/query/utils/promiseWithResolvers.ts b/packages/toolkit/src/query/utils/promiseWithResolvers.ts new file mode 100644 index 0000000000..ebcc676ca3 --- /dev/null +++ b/packages/toolkit/src/query/utils/promiseWithResolvers.ts @@ -0,0 +1,67 @@ +import { safeAssign } from "../tsHelpers"; + +export interface PromiseConstructorWithKnownReason { + /** + * Creates a new Promise with a known rejection reason. + * @param executor A callback used to initialize the promise. This callback is passed two arguments: + * a resolve callback used to resolve the promise with a value or the result of another promise, + * and a reject callback used to reject the promise with a provided reason or error. + */ + new ( + executor: ( + resolve: (value: T | PromiseLike) => void, + reject: (reason?: R) => void + ) => void + ): PromiseWithKnownReason +} + +export interface PromiseWithKnownReason + extends Omit, 'then' | 'catch'> { + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then( + onfulfilled?: + | ((value: T) => TResult1 | PromiseLike) + | undefined + | null, + onrejected?: + | ((reason: R) => TResult2 | PromiseLike) + | undefined + | null + ): Promise + + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch( + onrejected?: + | ((reason: R) => TResult | PromiseLike) + | undefined + | null + ): Promise +} + +export const PromiseWithKnownReason = Promise as PromiseConstructorWithKnownReason + + +type PromiseExecutor = ConstructorParameters>[0]; + +export type PromiseWithResolvers = { + promise: PromiseWithKnownReason; + resolve: Parameters>[0]; + reject: Parameters>[1]; +}; + +export const promiseWithResolvers = (): PromiseWithResolvers => { + const result = {} as PromiseWithResolvers; + result.promise = new PromiseWithKnownReason((resolve, reject) => { + safeAssign(result, { reject, resolve }); + }); + return result; +}; From 319c77207a3c4fa9565c8707c74e9168893c5c7e Mon Sep 17 00:00:00 2001 From: Ben Durrant Date: Tue, 6 Jun 2023 23:00:22 +0100 Subject: [PATCH 12/24] require reason to ensure onrejected callback type is accurate --- packages/toolkit/src/query/utils/promiseWithResolvers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/toolkit/src/query/utils/promiseWithResolvers.ts b/packages/toolkit/src/query/utils/promiseWithResolvers.ts index ebcc676ca3..91a117d231 100644 --- a/packages/toolkit/src/query/utils/promiseWithResolvers.ts +++ b/packages/toolkit/src/query/utils/promiseWithResolvers.ts @@ -10,7 +10,7 @@ export interface PromiseConstructorWithKnownReason { new ( executor: ( resolve: (value: T | PromiseLike) => void, - reject: (reason?: R) => void + reject: (reason: R) => void ) => void ): PromiseWithKnownReason } From 8833de4ca6f543066e83272977b5d1dea5f88e90 Mon Sep 17 00:00:00 2001 From: Ben Durrant Date: Tue, 6 Jun 2023 23:40:26 +0100 Subject: [PATCH 13/24] export promiseWithResolvers from utils index --- .../src/query/core/buildMiddleware/queryLifecycle.ts | 7 ++----- packages/toolkit/src/query/utils/index.ts | 1 + 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/toolkit/src/query/core/buildMiddleware/queryLifecycle.ts b/packages/toolkit/src/query/core/buildMiddleware/queryLifecycle.ts index 2a2a6740a9..b15816d8c6 100644 --- a/packages/toolkit/src/query/core/buildMiddleware/queryLifecycle.ts +++ b/packages/toolkit/src/query/core/buildMiddleware/queryLifecycle.ts @@ -11,11 +11,8 @@ import type { InternalHandlerBuilder, ApiMiddlewareInternalHandler, } from './types' -import type { - PromiseWithKnownReason, - PromiseWithResolvers, -} from '../../utils/promiseWithResolvers' -import { promiseWithResolvers } from '../../utils/promiseWithResolvers' +import type { PromiseWithKnownReason, PromiseWithResolvers } from '../../utils' +import { promiseWithResolvers } from '../../utils' export type ReferenceQueryLifecycle = never diff --git a/packages/toolkit/src/query/utils/index.ts b/packages/toolkit/src/query/utils/index.ts index 46694a2c3f..f144dd0ce0 100644 --- a/packages/toolkit/src/query/utils/index.ts +++ b/packages/toolkit/src/query/utils/index.ts @@ -6,3 +6,4 @@ export * from './capitalize' export * from './isOnline' export * from './isDocumentVisible' export * from './copyWithStructuralSharing' +export * from './promiseWithResolvers' From 7e3f4a535cb91d63b8e54eb2484ab914443a2b34 Mon Sep 17 00:00:00 2001 From: Ben Durrant Date: Tue, 6 Jun 2023 23:43:44 +0100 Subject: [PATCH 14/24] use utils index --- .../src/query/core/buildMiddleware/cacheLifecycle.ts | 4 ++-- packages/toolkit/src/query/utils/index.ts | 11 ++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/packages/toolkit/src/query/core/buildMiddleware/cacheLifecycle.ts b/packages/toolkit/src/query/core/buildMiddleware/cacheLifecycle.ts index 2f5ea7811b..648d3badb4 100644 --- a/packages/toolkit/src/query/core/buildMiddleware/cacheLifecycle.ts +++ b/packages/toolkit/src/query/core/buildMiddleware/cacheLifecycle.ts @@ -15,8 +15,8 @@ import type { InternalHandlerBuilder, SubMiddlewareApi, } from './types' -import type { PromiseWithKnownReason } from '../../utils/promiseWithResolvers' -import { promiseWithResolvers } from '../../utils/promiseWithResolvers' +import type { PromiseWithKnownReason } from '../../utils' +import { promiseWithResolvers } from '../../utils' export type ReferenceCacheLifecycle = never diff --git a/packages/toolkit/src/query/utils/index.ts b/packages/toolkit/src/query/utils/index.ts index f144dd0ce0..31a2061c34 100644 --- a/packages/toolkit/src/query/utils/index.ts +++ b/packages/toolkit/src/query/utils/index.ts @@ -1,9 +1,10 @@ +export * from './capitalize' +export * from './copyWithStructuralSharing' +export * from './flatten' export * from './isAbsoluteUrl' +export * from './isDocumentVisible' +export * from './isNotNullish' +export * from './isOnline' export * from './isValidUrl' export * from './joinUrls' -export * from './flatten' -export * from './capitalize' -export * from './isOnline' -export * from './isDocumentVisible' -export * from './copyWithStructuralSharing' export * from './promiseWithResolvers' From bb7451cb8281018ba41ac3aa5b0b8ba37153d73c Mon Sep 17 00:00:00 2001 From: Ben Durrant Date: Tue, 6 Jun 2023 23:55:58 +0100 Subject: [PATCH 15/24] add promiseWithResolvers test --- .../toolkit/src/query/tests/utils.test.ts | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/packages/toolkit/src/query/tests/utils.test.ts b/packages/toolkit/src/query/tests/utils.test.ts index 1124f0294b..9cfffbaa0d 100644 --- a/packages/toolkit/src/query/tests/utils.test.ts +++ b/packages/toolkit/src/query/tests/utils.test.ts @@ -4,6 +4,7 @@ import { isDocumentVisible, flatten, joinUrls, + promiseWithResolvers, } from '@internal/query/utils' afterAll(() => { @@ -107,3 +108,30 @@ describe('flatten', () => { expect(flattenResult).toEqual([1, 2, 3, 4, [5, 6]]) }) }) + +describe('promiseWithResolvers', () => { + test('provides promise along with lifecycle methods', async () => { + const stringPromise = promiseWithResolvers() + + stringPromise.resolve('foo') + + if (2 < 1) { + // only type test this + // @ts-expect-error + stringPromise.resolve(0) + } + + await expect(stringPromise.promise).resolves.toBe('foo') + + const thrownPromise = promiseWithResolvers() + + thrownPromise.reject('an error') + + if (2 < 1) { + // @ts-expect-error + thrownPromise.reject(0) + } + + await expect(thrownPromise.promise).rejects.toThrow('an error') + }) +}) From fb8a1aad262961f72752f28f915a42f283555696 Mon Sep 17 00:00:00 2001 From: "ben.durrant" Date: Mon, 2 Oct 2023 21:28:48 +0100 Subject: [PATCH 16/24] lockfile --- yarn.lock | 174 ++---------------------------------------------------- 1 file changed, 6 insertions(+), 168 deletions(-) diff --git a/yarn.lock b/yarn.lock index 9e1cf99503..817377d48e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5983,15 +5983,6 @@ __metadata: languageName: node linkType: hard -"@jest/expect-utils@npm:^29.5.0": - version: 29.5.0 - resolution: "@jest/expect-utils@npm:29.5.0" - dependencies: - jest-get-type: ^29.4.3 - checksum: c46fb677c88535cf83cf29f0a5b1f376c6a1109ddda266ad7da1a9cbc53cb441fa402dd61fc7b111ffc99603c11a9b3357ee41a1c0e035a58830bcb360871476 - languageName: node - linkType: hard - "@jest/expect@npm:^29.3.1": version: 29.3.1 resolution: "@jest/expect@npm:29.3.1" @@ -6146,15 +6137,6 @@ __metadata: languageName: node linkType: hard -"@jest/schemas@npm:^29.4.3": - version: 29.4.3 - resolution: "@jest/schemas@npm:29.4.3" - dependencies: - "@sinclair/typebox": ^0.25.16 - checksum: ac754e245c19dc39e10ebd41dce09040214c96a4cd8efa143b82148e383e45128f24599195ab4f01433adae4ccfbe2db6574c90db2862ccd8551a86704b5bebd - languageName: node - linkType: hard - "@jest/source-map@npm:^27.5.1": version: 27.5.1 resolution: "@jest/source-map@npm:27.5.1" @@ -6360,20 +6342,6 @@ __metadata: languageName: node linkType: hard -"@jest/types@npm:^29.5.0": - version: 29.5.0 - resolution: "@jest/types@npm:29.5.0" - dependencies: - "@jest/schemas": ^29.4.3 - "@types/istanbul-lib-coverage": ^2.0.0 - "@types/istanbul-reports": ^3.0.0 - "@types/node": "*" - "@types/yargs": ^17.0.8 - chalk: ^4.0.0 - checksum: 1811f94b19cf8a9460a289c4f056796cfc373480e0492692a6125a553cd1a63824bd846d7bb78820b7b6f758f6dd3c2d4558293bb676d541b2fa59c70fdf9d39 - languageName: node - linkType: hard - "@jridgewell/gen-mapping@npm:^0.1.0": version: 0.1.1 resolution: "@jridgewell/gen-mapping@npm:0.1.1" @@ -7347,13 +7315,6 @@ __metadata: languageName: node linkType: hard -"@sinclair/typebox@npm:^0.25.16": - version: 0.25.24 - resolution: "@sinclair/typebox@npm:0.25.24" - checksum: 10219c58f40b8414c50b483b0550445e9710d4fe7b2c4dccb9b66533dd90ba8e024acc776026cebe81e87f06fa24b07fdd7bc30dd277eb9cc386ec50151a3026 - languageName: node - linkType: hard - "@sindresorhus/is@npm:^0.14.0": version: 0.14.0 resolution: "@sindresorhus/is@npm:0.14.0" @@ -8217,16 +8178,6 @@ __metadata: languageName: node linkType: hard -"@types/jest@npm:^29": - version: 29.5.2 - resolution: "@types/jest@npm:29.5.2" - dependencies: - expect: ^29.0.0 - pretty-format: ^29.0.0 - checksum: 7d205599ea3cccc262bad5cc173d3242d6bf8138c99458509230e4ecef07a52d6ddcde5a1dbd49ace655c0af51d2dbadef3748697292ea4d86da19d9e03e19c0 - languageName: node - linkType: hard - "@types/js-levenshtein@npm:^1.1.1": version: 1.1.1 resolution: "@types/js-levenshtein@npm:1.1.1" @@ -8241,13 +8192,13 @@ __metadata: languageName: node linkType: hard -"@types/jscodeshift@npm:^0.11.6": - version: 0.11.6 - resolution: "@types/jscodeshift@npm:0.11.6" +"@types/jscodeshift@npm:^0.11.5": + version: 0.11.7 + resolution: "@types/jscodeshift@npm:0.11.7" dependencies: ast-types: ^0.14.1 recast: ^0.20.3 - checksum: 418d34488f74e711b37fcfce5129df3494d7fd30e852b3e80ff659ef0b1a4a83911e62883a10d7e1111316b569fa91a5a6a6d22fee86c2d69db829e25b534b27 + checksum: c6b81d537dca08c24db76e5e75d6056ef7c5b7651aebc319277321e2f2421984cc237ac71593dec374e49f9eae28c22150a37de3a572f141d55382c193091899 languageName: node linkType: hard @@ -13676,13 +13627,6 @@ __metadata: languageName: node linkType: hard -"diff-sequences@npm:^29.4.3": - version: 29.4.3 - resolution: "diff-sequences@npm:29.4.3" - checksum: 28b265e04fdddcf7f9f814effe102cc95a9dec0564a579b5aed140edb24fc345c611ca52d76d725a3cab55d3888b915b5e8a4702e0f6058968a90fa5f41fcde7 - languageName: node - linkType: hard - "diff@npm:^4.0.1": version: 4.0.2 resolution: "diff@npm:4.0.2" @@ -15153,19 +15097,6 @@ __metadata: languageName: node linkType: hard -"expect@npm:^29.0.0": - version: 29.5.0 - resolution: "expect@npm:29.5.0" - dependencies: - "@jest/expect-utils": ^29.5.0 - jest-get-type: ^29.4.3 - jest-matcher-utils: ^29.5.0 - jest-message-util: ^29.5.0 - jest-util: ^29.5.0 - checksum: 58f70b38693df6e5c6892db1bcd050f0e518d6f785175dc53917d4fa6a7359a048e5690e19ddcb96b65c4493881dd89a3dabdab1a84dfa55c10cdbdabf37b2d7 - languageName: node - linkType: hard - "expect@npm:^29.3.1": version: 29.3.1 resolution: "expect@npm:29.3.1" @@ -18572,18 +18503,6 @@ fsevents@^1.2.7: languageName: node linkType: hard -"jest-diff@npm:^29.5.0": - version: 29.5.0 - resolution: "jest-diff@npm:29.5.0" - dependencies: - chalk: ^4.0.0 - diff-sequences: ^29.4.3 - jest-get-type: ^29.4.3 - pretty-format: ^29.5.0 - checksum: dfd0f4a299b5d127779c76b40106c37854c89c3e0785098c717d52822d6620d227f6234c3a9291df204d619e799e3654159213bf93220f79c8e92a55475a3d39 - languageName: node - linkType: hard - "jest-docblock@npm:^27.5.1": version: 27.5.1 resolution: "jest-docblock@npm:27.5.1" @@ -18692,13 +18611,6 @@ fsevents@^1.2.7: languageName: node linkType: hard -"jest-get-type@npm:^29.4.3": - version: 29.4.3 - resolution: "jest-get-type@npm:29.4.3" - checksum: 6ac7f2dde1c65e292e4355b6c63b3a4897d7e92cb4c8afcf6d397f2682f8080e094c8b0b68205a74d269882ec06bf696a9de6cd3e1b7333531e5ed7b112605ce - languageName: node - linkType: hard - "jest-haste-map@npm:^26.6.2": version: 26.6.2 resolution: "jest-haste-map@npm:26.6.2" @@ -18840,18 +18752,6 @@ fsevents@^1.2.7: languageName: node linkType: hard -"jest-matcher-utils@npm:^29.5.0": - version: 29.5.0 - resolution: "jest-matcher-utils@npm:29.5.0" - dependencies: - chalk: ^4.0.0 - jest-diff: ^29.5.0 - jest-get-type: ^29.4.3 - pretty-format: ^29.5.0 - checksum: 1d3e8c746e484a58ce194e3aad152eff21fd0896e8b8bf3d4ab1a4e2cbfed95fb143646f4ad9fdf6e42212b9e8fc033268b58e011b044a9929df45485deb5ac9 - languageName: node - linkType: hard - "jest-message-util@npm:^27.5.1": version: 27.5.1 resolution: "jest-message-util@npm:27.5.1" @@ -18903,23 +18803,6 @@ fsevents@^1.2.7: languageName: node linkType: hard -"jest-message-util@npm:^29.5.0": - version: 29.5.0 - resolution: "jest-message-util@npm:29.5.0" - dependencies: - "@babel/code-frame": ^7.12.13 - "@jest/types": ^29.5.0 - "@types/stack-utils": ^2.0.0 - chalk: ^4.0.0 - graceful-fs: ^4.2.9 - micromatch: ^4.0.4 - pretty-format: ^29.5.0 - slash: ^3.0.0 - stack-utils: ^2.0.3 - checksum: daddece6bbf846eb6a2ab9be9f2446e54085bef4e5cecd13d2a538fa9c01cb89d38e564c6b74fd8e12d37ed9eface8a362240ae9f21d68b214590631e7a0d8bf - languageName: node - linkType: hard - "jest-mock@npm:^27.5.1": version: 27.5.1 resolution: "jest-mock@npm:27.5.1" @@ -19263,20 +19146,6 @@ fsevents@^1.2.7: languageName: node linkType: hard -"jest-util@npm:^29.5.0": - version: 29.5.0 - resolution: "jest-util@npm:29.5.0" - dependencies: - "@jest/types": ^29.5.0 - "@types/node": "*" - chalk: ^4.0.0 - ci-info: ^3.2.0 - graceful-fs: ^4.2.9 - picomatch: ^2.2.3 - checksum: fd9212950d34d2ecad8c990dda0d8ea59a8a554b0c188b53ea5d6c4a0829a64f2e1d49e6e85e812014933d17426d7136da4785f9cf76fff1799de51b88bc85d3 - languageName: node - linkType: hard - "jest-validate@npm:^27.5.1": version: 27.5.1 resolution: "jest-validate@npm:27.5.1" @@ -24052,17 +23921,6 @@ fsevents@^1.2.7: languageName: node linkType: hard -"pretty-format@npm:^29.0.0, pretty-format@npm:^29.5.0": - version: 29.5.0 - resolution: "pretty-format@npm:29.5.0" - dependencies: - "@jest/schemas": ^29.4.3 - ansi-styles: ^5.0.0 - react-is: ^18.0.0 - checksum: 4065356b558e6db25b4d41a01efb386935a6c06a0c9c104ef5ce59f2f476b8210edb8b3949b386e60ada0a6dc5ebcb2e6ccddc8c64dfd1a9943c3c3a9e7eaf89 - languageName: node - linkType: hard - "pretty-format@npm:^29.3.1": version: 29.3.1 resolution: "pretty-format@npm:29.3.1" @@ -28671,7 +28529,7 @@ fsevents@^1.2.7: languageName: node linkType: hard -"typescript@npm:^4.9": +"typescript@npm:^4.8.0, typescript@npm:^4.9": version: 4.9.5 resolution: "typescript@npm:4.9.5" bin: @@ -28681,16 +28539,6 @@ fsevents@^1.2.7: languageName: node linkType: hard -"typescript@npm:^5": - version: 5.1.3 - resolution: "typescript@npm:5.1.3" - bin: - tsc: bin/tsc - tsserver: bin/tsserver - checksum: d9d51862d98efa46534f2800a1071a613751b1585dc78884807d0c179bcd93d6e9d4012a508e276742f5f33c480adefc52ffcafaf9e0e00ab641a14cde9a31c7 - languageName: node - linkType: hard - "typescript@npm:~4.2.4": version: 4.2.4 resolution: "typescript@npm:4.2.4" @@ -28741,7 +28589,7 @@ fsevents@^1.2.7: languageName: node linkType: hard -"typescript@patch:typescript@^4.9#~builtin": +"typescript@patch:typescript@^4.8.0#~builtin, typescript@patch:typescript@^4.9#~builtin": version: 4.9.5 resolution: "typescript@patch:typescript@npm%3A4.9.5#~builtin::version=4.9.5&hash=701156" bin: @@ -28751,16 +28599,6 @@ fsevents@^1.2.7: languageName: node linkType: hard -"typescript@patch:typescript@^5#~builtin": - version: 5.1.3 - resolution: "typescript@patch:typescript@npm%3A5.1.3#~builtin::version=5.1.3&hash=701156" - bin: - tsc: bin/tsc - tsserver: bin/tsserver - checksum: 32a25b2e128a4616f999d4ee502aabb1525d5647bc8955e6edf05d7fbc53af8aa98252e2f6ba80bcedfc0260c982b885f3c09cfac8bb65d2924f3133ad1e1e62 - languageName: node - linkType: hard - "typescript@patch:typescript@~4.2.4#~builtin": version: 4.2.4 resolution: "typescript@patch:typescript@npm%3A4.2.4#~builtin::version=4.2.4&hash=701156" From 948f6d9f53c0eefffb587cae402b28fb8a6811ff Mon Sep 17 00:00:00 2001 From: Ben Durrant Date: Mon, 29 Jan 2024 16:22:57 +0000 Subject: [PATCH 17/24] run prettier --- .../transforms/enhanceEndpoint/test.js | 8 +- .../toolkit/src/query/endpointDefinitions.ts | 91 ++++++++++--------- .../src/query/utils/promiseWithResolvers.ts | 41 +++++---- 3 files changed, 73 insertions(+), 67 deletions(-) diff --git a/packages/rtk-codemods/transforms/enhanceEndpoint/test.js b/packages/rtk-codemods/transforms/enhanceEndpoint/test.js index 2fa121219b..9196c9e1d6 100644 --- a/packages/rtk-codemods/transforms/enhanceEndpoint/test.js +++ b/packages/rtk-codemods/transforms/enhanceEndpoint/test.js @@ -1,9 +1,9 @@ -'use strict'; +'use strict' -const { runTransformTest } = require('codemod-cli'); +const { runTransformTest } = require('codemod-cli') runTransformTest({ name: 'enhanceEndpoint', path: require.resolve('./index.ts'), - fixtureDir: `${__dirname}/__testfixtures__/`, -}); + fixtureDir: `${__dirname}/__testfixtures__/` +}) diff --git a/packages/toolkit/src/query/endpointDefinitions.ts b/packages/toolkit/src/query/endpointDefinitions.ts index 606e69a171..9802f7ba09 100644 --- a/packages/toolkit/src/query/endpointDefinitions.ts +++ b/packages/toolkit/src/query/endpointDefinitions.ts @@ -814,7 +814,7 @@ export type OverrideResultType = export type AddTagTypes< Definitions extends EndpointDefinitions, - NewTagTypes extends string + NewTagTypes extends string, > = { [K in keyof Definitions]: Definitions[K] extends QueryDefinition< infer QueryArg, @@ -825,55 +825,56 @@ export type AddTagTypes< > ? QueryDefinition : Definitions[K] extends MutationDefinition< - infer QueryArg, - infer BaseQuery, - any, - infer ResultType, - infer ReducerPath - > - ? MutationDefinition< - QueryArg, - BaseQuery, - NewTagTypes, - ResultType, - ReducerPath - > - : never + infer QueryArg, + infer BaseQuery, + any, + infer ResultType, + infer ReducerPath + > + ? MutationDefinition< + QueryArg, + BaseQuery, + NewTagTypes, + ResultType, + ReducerPath + > + : never } export type EnhanceEndpoint< Definition extends EndpointDefinition, NewQueryArg, - NewResultType -> = Definition extends QueryDefinition< - any, - infer BaseQuery, - infer TagTypes, - any, - infer ReducerPath -> - ? QueryDefinition< - NewQueryArg, - BaseQuery, - TagTypes, - NewResultType, - ReducerPath - > - : Definition extends MutationDefinition< - any, - infer BaseQuery, - infer TagTypes, - any, - infer ReducerPath - > - ? MutationDefinition< - NewQueryArg, - BaseQuery, - TagTypes, - NewResultType, - ReducerPath - > - : never + NewResultType, +> = + Definition extends QueryDefinition< + any, + infer BaseQuery, + infer TagTypes, + any, + infer ReducerPath + > + ? QueryDefinition< + NewQueryArg, + BaseQuery, + TagTypes, + NewResultType, + ReducerPath + > + : Definition extends MutationDefinition< + any, + infer BaseQuery, + infer TagTypes, + any, + infer ReducerPath + > + ? MutationDefinition< + NewQueryArg, + BaseQuery, + TagTypes, + NewResultType, + ReducerPath + > + : never export type UpdateDefinitions< Definitions extends EndpointDefinitions, diff --git a/packages/toolkit/src/query/utils/promiseWithResolvers.ts b/packages/toolkit/src/query/utils/promiseWithResolvers.ts index 91a117d231..eb8c926270 100644 --- a/packages/toolkit/src/query/utils/promiseWithResolvers.ts +++ b/packages/toolkit/src/query/utils/promiseWithResolvers.ts @@ -1,4 +1,4 @@ -import { safeAssign } from "../tsHelpers"; +import { safeAssign } from '../tsHelpers' export interface PromiseConstructorWithKnownReason { /** @@ -10,8 +10,8 @@ export interface PromiseConstructorWithKnownReason { new ( executor: ( resolve: (value: T | PromiseLike) => void, - reject: (reason: R) => void - ) => void + reject: (reason: R) => void, + ) => void, ): PromiseWithKnownReason } @@ -31,7 +31,7 @@ export interface PromiseWithKnownReason onrejected?: | ((reason: R) => TResult2 | PromiseLike) | undefined - | null + | null, ): Promise /** @@ -43,25 +43,30 @@ export interface PromiseWithKnownReason onrejected?: | ((reason: R) => TResult | PromiseLike) | undefined - | null + | null, ): Promise } -export const PromiseWithKnownReason = Promise as PromiseConstructorWithKnownReason - +export const PromiseWithKnownReason = + Promise as PromiseConstructorWithKnownReason -type PromiseExecutor = ConstructorParameters>[0]; +type PromiseExecutor = ConstructorParameters< + typeof PromiseWithKnownReason +>[0] export type PromiseWithResolvers = { - promise: PromiseWithKnownReason; - resolve: Parameters>[0]; - reject: Parameters>[1]; -}; + promise: PromiseWithKnownReason + resolve: Parameters>[0] + reject: Parameters>[1] +} -export const promiseWithResolvers = (): PromiseWithResolvers => { - const result = {} as PromiseWithResolvers; +export const promiseWithResolvers = (): PromiseWithResolvers< + T, + R +> => { + const result = {} as PromiseWithResolvers result.promise = new PromiseWithKnownReason((resolve, reject) => { - safeAssign(result, { reject, resolve }); - }); - return result; -}; + safeAssign(result, { reject, resolve }) + }) + return result +} From c5da0682f184763b5731fb50b617cab2bc4a2df3 Mon Sep 17 00:00:00 2001 From: Ben Durrant Date: Mon, 29 Jan 2024 17:53:50 +0000 Subject: [PATCH 18/24] fix tests to avoid enhanceEndpoints --- packages/toolkit/src/query/apiTypes.ts | 2 +- .../src/query/tests/createApi.test-d.ts | 164 +++++++----------- 2 files changed, 65 insertions(+), 101 deletions(-) diff --git a/packages/toolkit/src/query/apiTypes.ts b/packages/toolkit/src/query/apiTypes.ts index fe24f69ad3..d206954291 100644 --- a/packages/toolkit/src/query/apiTypes.ts +++ b/packages/toolkit/src/query/apiTypes.ts @@ -114,8 +114,8 @@ export type BaseApiMethods< */ enhanceEndpoint< QueryName extends QueryKeys, - QueryArg = QueryArgFrom, ResultType = ResultTypeFrom, + QueryArg = QueryArgFrom, >( queryName: QueryName, partialDefinition: diff --git a/packages/toolkit/src/query/tests/createApi.test-d.ts b/packages/toolkit/src/query/tests/createApi.test-d.ts index b33ced1f6e..9117a3d26f 100644 --- a/packages/toolkit/src/query/tests/createApi.test-d.ts +++ b/packages/toolkit/src/query/tests/createApi.test-d.ts @@ -2,13 +2,10 @@ import { setupApiStore } from '@internal/tests/utils/helpers' import type { SerializedError } from '@reduxjs/toolkit' import { configureStore } from '@reduxjs/toolkit' import type { - DefinitionsFromApi, FetchBaseQueryError, MutationDefinition, - OverrideResultType, QueryDefinition, TagDescription, - TagTypesFromApi, } from '@reduxjs/toolkit/query' import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query' @@ -212,48 +209,25 @@ describe('type tests', () => { withoutTestLifecycles: true, }) - api1.enhanceEndpoints({ - endpoints: { - query1: { - // @ts-expect-error - providesTags: ['new'], - }, - query2: { - // @ts-expect-error - providesTags: ['missing'], - }, - }, - }) + // @ts-expect-error + api1 + .enhanceEndpoint('query1', { + providesTags: ['new'], + }) + .enhanceEndpoint('query2', { + providesTags: ['missing'], + }) - const enhanced = api1.enhanceEndpoints({ - addTagTypes: ['new'], - endpoints: { - query1: { - providesTags: ['new'], - }, - query2: { - // @ts-expect-error - providesTags: ['missing'], - }, - }, - }) + const enhanced = api1 + .addTagTypes('new') + .enhanceEndpoint('query1', { providesTags: ['new'] }) + + // @ts-expect-error + enhanced.enhanceEndpoint('query2', { providesTags: ['missing'] }) storeRef.store.dispatch(api1.endpoints.query1.initiate('in1')) storeRef.store.dispatch(api1.endpoints.query2.initiate('in2')) - - enhanced.enhanceEndpoints({ - endpoints: { - query1: { - // returned `enhanced` api contains "new" entityType - providesTags: ['new'], - }, - query2: { - // @ts-expect-error - providesTags: ['missing'], - }, - }, - }) }) test('modify', () => { @@ -261,40 +235,38 @@ describe('type tests', () => { withoutTestLifecycles: true, }) - api1.enhanceEndpoints({ - endpoints: { - query1: { - query: (x) => { - expectTypeOf(x).toEqualTypeOf<'in1'>() + api1 + .enhanceEndpoint('query1', { + query: (x) => { + expectTypeOf(x).toEqualTypeOf<'in1'>() - return 'modified1' - }, + return 'modified1' }, - query2(definition) { - definition.query = (x) => { - expectTypeOf(x).toEqualTypeOf<'in2'>() + }) + .enhanceEndpoint('query2', (definition) => { + definition.query = (x) => { + expectTypeOf(x).toEqualTypeOf<'in2'>() + + return 'modified2' + } + }) + .enhanceEndpoint('mutation1', { + query: (x) => { + expectTypeOf(x).toEqualTypeOf<'in1'>() - return 'modified2' - } + return 'modified1' }, - mutation1: { - query: (x) => { - expectTypeOf(x).toEqualTypeOf<'in1'>() + }) + .enhanceEndpoint('mutation2', (definition) => { + definition.query = (x) => { + expectTypeOf(x).toEqualTypeOf<'in2'>() - return 'modified1' - }, - }, - mutation2(definition) { - definition.query = (x) => { - expectTypeOf(x).toEqualTypeOf<'in2'>() + return 'modified2' + } + }) - return 'modified2' - } - }, - // @ts-expect-error - nonExisting: {}, - }, - }) + // @ts-expect-error + api1.enhanceEndpoint('nonexisting', {}) storeRef.store.dispatch(api1.endpoints.query1.initiate('in1')) storeRef.store.dispatch(api1.endpoints.query2.initiate('in2')) @@ -314,42 +286,34 @@ describe('type tests', () => { type Transformed = { value: string } - type Definitions = DefinitionsFromApi - - type TagTypes = TagTypesFromApi - - type Q1Definition = OverrideResultType< - Definitions['query1'], - Transformed - > - - type M1Definition = OverrideResultType< - Definitions['mutation1'], - Transformed - > + const enhancedApi = baseApi + .enhanceEndpoint('query1', { + transformResponse: (a, b, c) => ({ + value: 'transformed', + }), + }) + .enhanceEndpoint('mutation1', { + transformResponse: (a, b, c) => ({ + value: 'transformed', + }), + }) - type UpdatedDefinitions = Omit & { - query1: Q1Definition - mutation1: M1Definition - } + // generics need to be provided manually if using callback enhancer - const enhancedApi = baseApi.enhanceEndpoints< - TagTypes, - UpdatedDefinitions - >({ - endpoints: { - query1: { - transformResponse: (a, b, c) => ({ - value: 'transformed', - }), - }, - mutation1: { - transformResponse: (a, b, c) => ({ + const enhancedApi2 = baseApi + .enhanceEndpoint<'query1', Transformed>('query1', (definition) => { + definition.transformResponse = (a, b, c) => ({ + value: 'transformed', + }) + }) + .enhanceEndpoint<'mutation1', Transformed>( + 'mutation1', + (definition) => { + definition.transformResponse = (a, b, c) => ({ value: 'transformed', - }), + }) }, - }, - }) + ) const storeRef = setupApiStore(enhancedApi, undefined, { withoutTestLifecycles: true, From 31707ebd4940f9c332c35a97c00ee066d4722fcc Mon Sep 17 00:00:00 2001 From: Ben Durrant Date: Mon, 29 Jan 2024 18:21:00 +0000 Subject: [PATCH 19/24] fix fixedCacheKey test --- .../tests/useMutation-fixedCacheKey.test.tsx | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/packages/toolkit/src/query/tests/useMutation-fixedCacheKey.test.tsx b/packages/toolkit/src/query/tests/useMutation-fixedCacheKey.test.tsx index 5ab0d8f215..f4a3961445 100644 --- a/packages/toolkit/src/query/tests/useMutation-fixedCacheKey.test.tsx +++ b/packages/toolkit/src/query/tests/useMutation-fixedCacheKey.test.tsx @@ -359,12 +359,8 @@ describe('fixedCacheKey', () => { }) test('using fixedCacheKey should create a new cache entry', async () => { - api.enhanceEndpoints({ - endpoints: { - send: { - onCacheEntryAdded: (arg) => onNewCacheEntry(arg), - }, - }, + api.enhanceEndpoint('send', { + onCacheEntryAdded: (arg) => onNewCacheEntry(arg), }) render(, { @@ -383,12 +379,8 @@ describe('fixedCacheKey', () => { expect(onNewCacheEntry).toHaveBeenCalledWith('C1') - api.enhanceEndpoints({ - endpoints: { - send: { - onCacheEntryAdded: undefined, - }, - }, + api.enhanceEndpoint('send', { + onCacheEntryAdded: undefined, }) }) }) From 49698cd30638bc3eab06cb11a3823e0d173b7d65 Mon Sep 17 00:00:00 2001 From: Ben Durrant Date: Mon, 29 Jan 2024 18:25:40 +0000 Subject: [PATCH 20/24] add enhanceEndpoints back as deprecated --- packages/toolkit/src/query/createApi.ts | 35 +++++++++---------------- 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/packages/toolkit/src/query/createApi.ts b/packages/toolkit/src/query/createApi.ts index feb41a57eb..6a3414ce80 100644 --- a/packages/toolkit/src/query/createApi.ts +++ b/packages/toolkit/src/query/createApi.ts @@ -330,29 +330,20 @@ export function buildCreateApi, ...Module[]]>( } return api }, - } as Api - - // add fallback for runtime - undocumented in TS - // @ts-ignore - api.enhanceEndpoints = ({ - addTagTypes, - endpoints, - }: { - addTagTypes?: string[] - endpoints?: Record - }) => { - if (addTagTypes) { - api.addTagTypes(...addTagTypes) - } - if (endpoints) { - for (const [endpointName, partialDefinition] of Object.entries( - endpoints, - )) { - ;(api.enhanceEndpoint as any)(endpointName, partialDefinition) + enhanceEndpoints({ addTagTypes, endpoints }) { + if (addTagTypes) { + api.addTagTypes(...addTagTypes) } - } - return api - } + if (endpoints) { + for (const [endpointName, partialDefinition] of Object.entries( + endpoints, + )) { + ;(api.enhanceEndpoint as any)(endpointName, partialDefinition) + } + } + return api + }, + } as Api const initializedModules = modules.map((m) => m.init(api as any, optionsWithDefaults as any, context), From fa4f0e43870c9eca65af37ce860da7869f5b16ce Mon Sep 17 00:00:00 2001 From: Ben Durrant Date: Mon, 29 Jan 2024 18:26:56 +0000 Subject: [PATCH 21/24] add the types as well --- packages/toolkit/src/query/apiTypes.ts | 28 ++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/packages/toolkit/src/query/apiTypes.ts b/packages/toolkit/src/query/apiTypes.ts index d206954291..3cd2d5f849 100644 --- a/packages/toolkit/src/query/apiTypes.ts +++ b/packages/toolkit/src/query/apiTypes.ts @@ -192,6 +192,34 @@ export type BaseApiMethods< TagTypes, Enhancers > + + /** + *A function to enhance a generated API with additional information. Useful with code-generation. + * @deprecated Please use `enhanceEndpoint` and `addTagType` instead + */ + enhanceEndpoints< + NewTagTypes extends string = never, + NewDefinitions extends EndpointDefinitions = never, + >(_: { + addTagTypes?: readonly NewTagTypes[] + endpoints?: UpdateDefinitions< + Definitions, + TagTypes | NoInfer, + NewDefinitions + > extends infer NewDefinitions + ? { + [K in keyof NewDefinitions]?: + | Partial + | ((definition: NewDefinitions[K]) => void) + } + : never + }): Api< + BaseQuery, + UpdateDefinitions, + ReducerPath, + TagTypes | NewTagTypes, + Enhancers + > } export type Api< From 7e53c8eedd908771657e683eb1cf9ff5a4429115 Mon Sep 17 00:00:00 2001 From: EskiMojo14 Date: Fri, 2 Feb 2024 20:09:21 +0000 Subject: [PATCH 22/24] try something --- packages/toolkit/src/query/apiTypes.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/toolkit/src/query/apiTypes.ts b/packages/toolkit/src/query/apiTypes.ts index 3cd2d5f849..b74d8d34ee 100644 --- a/packages/toolkit/src/query/apiTypes.ts +++ b/packages/toolkit/src/query/apiTypes.ts @@ -16,11 +16,11 @@ import type { WithRequiredProp, Id, } from './tsHelpers' -import type { CoreModule } from '@reduxjs/toolkit/query' import type { CreateApiOptions } from './createApi' import type { BaseQueryFn } from './baseQueryTypes' import type { CombinedState, MutationKeys, QueryKeys } from './core/apiState' import type { UnknownAction } from '@reduxjs/toolkit' +import type { CoreModule } from './core/module' export interface ApiModules< // eslint-disable-next-line @typescript-eslint/no-unused-vars From dc08e93809e937eb803a066260c912b20ac4cd22 Mon Sep 17 00:00:00 2001 From: Ben Durrant Date: Wed, 19 Jun 2024 13:47:08 +0100 Subject: [PATCH 23/24] update README version --- packages/rtk-codemods/transforms/enhanceEndpoint/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rtk-codemods/transforms/enhanceEndpoint/README.md b/packages/rtk-codemods/transforms/enhanceEndpoint/README.md index 88fa328a02..42242a3906 100644 --- a/packages/rtk-codemods/transforms/enhanceEndpoint/README.md +++ b/packages/rtk-codemods/transforms/enhanceEndpoint/README.md @@ -1,6 +1,6 @@ # enhanceEndpoint -Transforms enhanceEndpoints calls into addTagType and enhanceEndpoint calls, in preparation for RTK 2.0. +Transforms enhanceEndpoints calls into addTagType and enhanceEndpoint calls, in preparation for RTK 3.0. ## Usage From 675f261e8890764d5ca161ab1d1d56b2485d822e Mon Sep 17 00:00:00 2001 From: Ben Durrant Date: Wed, 19 Jun 2024 13:52:29 +0100 Subject: [PATCH 24/24] put code on one line, to account for error in different versions --- packages/toolkit/src/query/tests/createApi.test-d.ts | 11 +++-------- packages/toolkit/src/query/tests/createApi.test.ts | 12 +++--------- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/packages/toolkit/src/query/tests/createApi.test-d.ts b/packages/toolkit/src/query/tests/createApi.test-d.ts index 9117a3d26f..c066902914 100644 --- a/packages/toolkit/src/query/tests/createApi.test-d.ts +++ b/packages/toolkit/src/query/tests/createApi.test-d.ts @@ -209,14 +209,9 @@ describe('type tests', () => { withoutTestLifecycles: true, }) - // @ts-expect-error - api1 - .enhanceEndpoint('query1', { - providesTags: ['new'], - }) - .enhanceEndpoint('query2', { - providesTags: ['missing'], - }) + // @ts-expect-error the location of the error varies depending on TS version, so this needs to be one line + // prettier-ignore + api1.enhanceEndpoint('query1', { providesTags: ['new'] }).enhanceEndpoint('query2', { providesTags: ['missing'] }) const enhanced = api1 .addTagTypes('new') diff --git a/packages/toolkit/src/query/tests/createApi.test.ts b/packages/toolkit/src/query/tests/createApi.test.ts index d42fb80d76..30ead1054c 100644 --- a/packages/toolkit/src/query/tests/createApi.test.ts +++ b/packages/toolkit/src/query/tests/createApi.test.ts @@ -416,15 +416,9 @@ describe('endpoint definition typings', () => { }) } - // @ts-expect-error - const enhanced = api - .addTagTypes('new') - .enhanceEndpoint('query1', { - providesTags: ['new'], - }) - .enhanceEndpoint('query2', { - providesTags: ['missing'], - }) + // @ts-expect-error the location of the error varies depending on TS version, so this needs to be one line + // prettier-ignore + const enhanced = api.addTagTypes('new').enhanceEndpoint('query1', { providesTags: ['new'] }).enhanceEndpoint('query2', { providesTags: ['missing'] }) storeRef.store.dispatch(api.endpoints.query1.initiate('in1')) await delay(1)