diff --git a/packages/rtk-codemods/README.md b/packages/rtk-codemods/README.md index be04f2b53b..ab7f117881 100644 --- a/packages/rtk-codemods/README.md +++ b/packages/rtk-codemods/README.md @@ -27,6 +27,7 @@ node ./bin/cli.js path/of/files/ or/some**/*glob.js - [createReducerBuilder](transforms/createReducerBuilder/README.md) - [createSliceBuilder](transforms/createSliceBuilder/README.md) +- [createSliceReducerBuilder](transforms/createSliceReducerBuilder/README.md) ## Contributing diff --git a/packages/rtk-codemods/transforms/createReducerBuilder/README.md b/packages/rtk-codemods/transforms/createReducerBuilder/README.md index 52898146e9..a50d10d582 100644 --- a/packages/rtk-codemods/transforms/createReducerBuilder/README.md +++ b/packages/rtk-codemods/transforms/createReducerBuilder/README.md @@ -31,38 +31,159 @@ node ./bin/cli.js createReducerBuilder path/of/files/ or/some**/*glob.js ## +--- + **basic-ts** **Input** ([basic-ts.input.ts](transforms\createReducerBuilder__testfixtures__\basic-ts.input.ts)): ```ts -createReducer(initialState, { - [todoAdded]: (state: SliceState, action: PayloadAction) => { +import type { PayloadAction } from '@reduxjs/toolkit' +import { createEntityAdapter, createReducer } from '@reduxjs/toolkit' + +export interface Todo { + id: string + title: string +} + +export const todoAdapter = createEntityAdapter() + +const todoInitialState = todoAdapter.getInitialState() + +export type TodoSliceState = typeof todoInitialState + +const { addOne } = todoAdapter + +createReducer(todoInitialState, { + [todoAdded1a]: (state: TodoSliceState, action: PayloadAction) => { // stuff }, -}); + [todoAdded1b]: (state: TodoSliceState, action: PayloadAction) => + action.payload, + [todoAdded1c + 'test']: ( + state: TodoSliceState, + action: PayloadAction + ) => { + // stuff + }, + [todoAdded1d](state: TodoSliceState, action: PayloadAction) { + // stuff + }, + [todoAdded1e]: function ( + state: TodoSliceState, + action: PayloadAction + ) { + // stuff + }, + todoAdded1f: (state: TodoSliceState, action: PayloadAction) => { + //stuff + }, + [todoAdded1g]: addOne, + todoAdded1h: todoAdapter.addOne +}) -createReducer(initialState, { - [todoAdded](state: SliceState, action: PayloadAction) { +createReducer(todoInitialState, { + [todoAdded2a]: (state: TodoSliceState, action: PayloadAction) => { // stuff }, -}); + [todoAdded2b](state: TodoSliceState, action: PayloadAction) { + // stuff + }, + [todoAdded2c]: function ( + state: TodoSliceState, + action: PayloadAction + ) { + // stuff + } +}) ``` **Output** ([basic-ts.output.ts](transforms\createReducerBuilder__testfixtures__\basic-ts.output.ts)): ```ts -createReducer(initialState, (builder) => { - builder.addCase(todoAdded, (state: SliceState, action: PayloadAction) => { - // stuff - }); -}); - -createReducer(initialState, (builder) => { - builder.addCase(todoAdded, (state: SliceState, action: PayloadAction) => { - // stuff - }); -}); +import type { PayloadAction } from '@reduxjs/toolkit' +import { createEntityAdapter, createReducer } from '@reduxjs/toolkit' + +export interface Todo { + id: string + title: string +} + +export const todoAdapter = createEntityAdapter() + +const todoInitialState = todoAdapter.getInitialState() + +export type TodoSliceState = typeof todoInitialState + +const { addOne } = todoAdapter + +createReducer(todoInitialState, (builder) => { + builder.addCase( + todoAdded1a, + (state: TodoSliceState, action: PayloadAction) => { + // stuff + } + ) + + builder.addCase( + todoAdded1b, + (state: TodoSliceState, action: PayloadAction) => action.payload + ) + + builder.addCase( + todoAdded1c + 'test', + (state: TodoSliceState, action: PayloadAction) => { + // stuff + } + ) + + builder.addCase( + todoAdded1d, + (state: TodoSliceState, action: PayloadAction) => { + // stuff + } + ) + + builder.addCase( + todoAdded1e, + (state: TodoSliceState, action: PayloadAction) => { + // stuff + } + ) + + builder.addCase( + todoAdded1f, + (state: TodoSliceState, action: PayloadAction) => { + //stuff + } + ) + + builder.addCase(todoAdded1g, addOne) + builder.addCase(todoAdded1h, todoAdapter.addOne) +}) + +createReducer(todoInitialState, (builder) => { + builder.addCase( + todoAdded2a, + (state: TodoSliceState, action: PayloadAction) => { + // stuff + } + ) + + builder.addCase( + todoAdded2b, + (state: TodoSliceState, action: PayloadAction) => { + // stuff + } + ) + + builder.addCase( + todoAdded2c, + (state: TodoSliceState, action: PayloadAction) => { + // stuff + } + ) +}) ``` --- @@ -72,7 +193,15 @@ createReducer(initialState, (builder) => { **Input** ([basic.input.js](transforms\createReducerBuilder__testfixtures__\basic.input.js)): ```js -createReducer(initialState, { +import { createEntityAdapter, createReducer } from '@reduxjs/toolkit' + +export const todoAdapter = createEntityAdapter() + +const todoInitialState = todoAdapter.getInitialState() + +const { addOne } = todoAdapter + +createReducer(todoInitialState, { [todoAdded1a]: (state, action) => { // stuff }, @@ -89,9 +218,11 @@ createReducer(initialState, { todoAdded1f: (state, action) => { //stuff }, -}); + [todoAdded1g]: addOne, + todoAdded1h: todoAdapter.addOne +}) -createReducer(initialState, { +createReducer(todoInitialState, { [todoAdded2a]: (state, action) => { // stuff }, @@ -100,50 +231,61 @@ createReducer(initialState, { }, [todoAdded2c]: function (state, action) { // stuff - }, -}); + } +}) ``` **Output** ([basic.output.js](transforms\createReducerBuilder__testfixtures__\basic.output.js)): ```js -createReducer(initialState, (builder) => { +import { createEntityAdapter, createReducer } from '@reduxjs/toolkit' + +export const todoAdapter = createEntityAdapter() + +const todoInitialState = todoAdapter.getInitialState() + +const { addOne } = todoAdapter + +createReducer(todoInitialState, (builder) => { builder.addCase(todoAdded1a, (state, action) => { // stuff - }); + }) - builder.addCase(todoAdded1b, (state, action) => action.payload); + builder.addCase(todoAdded1b, (state, action) => action.payload) builder.addCase(todoAdded1c + 'test', (state, action) => { // stuff - }); + }) builder.addCase(todoAdded1d, (state, action) => { // stuff - }); + }) builder.addCase(todoAdded1e, (state, action) => { // stuff - }); + }) builder.addCase(todoAdded1f, (state, action) => { //stuff - }); -}); + }) + + builder.addCase(todoAdded1g, addOne) + builder.addCase(todoAdded1h, todoAdapter.addOne) +}) -createReducer(initialState, (builder) => { +createReducer(todoInitialState, (builder) => { builder.addCase(todoAdded2a, (state, action) => { // stuff - }); + }) builder.addCase(todoAdded2b, (state, action) => { // stuff - }); + }) builder.addCase(todoAdded2c, (state, action) => { // stuff - }); -}); + }) +}) ``` diff --git a/packages/rtk-codemods/transforms/createSliceBuilder/README.md b/packages/rtk-codemods/transforms/createSliceBuilder/README.md index 5a15c86682..725d80a4fa 100644 --- a/packages/rtk-codemods/transforms/createSliceBuilder/README.md +++ b/packages/rtk-codemods/transforms/createSliceBuilder/README.md @@ -31,56 +31,254 @@ node ./bin/cli.js createSliceBuilder path/of/files/ or/some**/*glob.js ## +--- + **basic-ts** **Input** ([basic-ts.input.ts](transforms\createSliceBuilder__testfixtures__\basic-ts.input.ts)): ```ts -const slice1 = createSlice({ - name: 'a', - initialState, +import type { PayloadAction } from '@reduxjs/toolkit' +import { + createAsyncThunk, + createEntityAdapter, + createSlice +} from '@reduxjs/toolkit' + +export interface Todo { + id: string + title: string +} + +export const todoAdapter = createEntityAdapter() + +const todoInitialState = todoAdapter.getInitialState() + +export type TodoSliceState = typeof todoInitialState + +const fetchCount = (amount = 1) => { + return new Promise<{ data: number }>((resolve) => + setTimeout(() => resolve({ data: amount }), 500) + ) +} + +export const incrementAsync = createAsyncThunk( + 'counter/fetchCount', + async (amount: number) => { + const response = await fetchCount(amount) + return response.data + } +) + +const { addOne } = todoAdapter + +const todoSlice = createSlice({ + name: 'todo', + initialState: todoInitialState, + reducers: { + deleteTodo: todoAdapter.removeOne + }, extraReducers: { - [todoAdded]: (state: SliceState, action: PayloadAction) => { + [incrementAsync.pending]: ( + state: TodoSliceState, + action: PayloadAction + ) => { // stuff }, - }, -}); + [incrementAsync.rejected]: todoAdapter.removeAll, + [incrementAsync.fulfilled]( + state: TodoSliceState, + action: PayloadAction + ) { + // stuff + }, + todoAdded: todoAdapter.addOne, -const slice2 = createSlice({ - name: 'b', - initialState, - extraReducers: { - [todoAdded](state: SliceState, action: PayloadAction) { + [todoAdded1a]: (state: TodoSliceState, action: PayloadAction) => { // stuff }, - }, -}); + [todoAdded1b]: (state: TodoSliceState, action: PayloadAction) => + action.payload, + [todoAdded1c + 'test']: ( + state: TodoSliceState, + action: PayloadAction + ) => { + // stuff + }, + [todoAdded1d](state: TodoSliceState, action: PayloadAction) { + // stuff + }, + [todoAdded1e]: function ( + state: TodoSliceState, + action: PayloadAction + ) { + // stuff + }, + todoAdded1f: (state: TodoSliceState, action: PayloadAction) => { + //stuff + }, + [todoAdded1g]: addOne, + todoAdded1h: todoAdapter.addOne + } +}) + +export const { deleteTodo } = todoSlice.actions + +export interface CounterSliceState { + value: number + status: 'idle' | 'loading' | 'failed' +} + +const counterInitialState: CounterSliceState = { + value: 0, + status: 'idle' +} + +const counterSlice = createSlice({ + name: 'counter', + initialState: counterInitialState, + extraReducers: { + [deleteTodo](state: CounterSliceState, action: PayloadAction) { + // stuff + } + } +}) ``` **Output** ([basic-ts.output.ts](transforms\createSliceBuilder__testfixtures__\basic-ts.output.ts)): ```ts -const slice1 = createSlice({ - name: 'a', - initialState, - - extraReducers: (builder) => { - builder.addCase(todoAdded, (state: SliceState, action: PayloadAction) => { - // stuff - }); +import type { PayloadAction } from '@reduxjs/toolkit' +import { + createAsyncThunk, + createEntityAdapter, + createSlice +} from '@reduxjs/toolkit' + +export interface Todo { + id: string + title: string +} + +export const todoAdapter = createEntityAdapter() + +const todoInitialState = todoAdapter.getInitialState() + +export type TodoSliceState = typeof todoInitialState + +const fetchCount = (amount = 1) => { + return new Promise<{ data: number }>((resolve) => + setTimeout(() => resolve({ data: amount }), 500) + ) +} + +export const incrementAsync = createAsyncThunk( + 'counter/fetchCount', + async (amount: number) => { + const response = await fetchCount(amount) + return response.data + } +) + +const { addOne } = todoAdapter + +const todoSlice = createSlice({ + name: 'todo', + initialState: todoInitialState, + + reducers: { + deleteTodo: todoAdapter.removeOne }, -}); -const slice2 = createSlice({ - name: 'b', - initialState, + extraReducers: (builder) => { + builder.addCase( + incrementAsync.pending, + (state: TodoSliceState, action: PayloadAction) => { + // stuff + } + ) + + builder.addCase(incrementAsync.rejected, todoAdapter.removeAll) + + builder.addCase( + incrementAsync.fulfilled, + (state: TodoSliceState, action: PayloadAction) => { + // stuff + } + ) + + builder.addCase(todoAdded, todoAdapter.addOne) + + builder.addCase( + todoAdded1a, + (state: TodoSliceState, action: PayloadAction) => { + // stuff + } + ) + + builder.addCase( + todoAdded1b, + (state: TodoSliceState, action: PayloadAction) => action.payload + ) + + builder.addCase( + todoAdded1c + 'test', + (state: TodoSliceState, action: PayloadAction) => { + // stuff + } + ) + + builder.addCase( + todoAdded1d, + (state: TodoSliceState, action: PayloadAction) => { + // stuff + } + ) + + builder.addCase( + todoAdded1e, + (state: TodoSliceState, action: PayloadAction) => { + // stuff + } + ) + + builder.addCase( + todoAdded1f, + (state: TodoSliceState, action: PayloadAction) => { + //stuff + } + ) + + builder.addCase(todoAdded1g, addOne) + builder.addCase(todoAdded1h, todoAdapter.addOne) + } +}) + +export const { deleteTodo } = todoSlice.actions + +export interface CounterSliceState { + value: number + status: 'idle' | 'loading' | 'failed' +} + +const counterInitialState: CounterSliceState = { + value: 0, + status: 'idle' +} + +const counterSlice = createSlice({ + name: 'counter', + initialState: counterInitialState, extraReducers: (builder) => { - builder.addCase(todoAdded, (state: SliceState, action: PayloadAction) => { - // stuff - }); - }, -}); + builder.addCase( + deleteTodo, + (state: CounterSliceState, action: PayloadAction) => { + // stuff + } + ) + } +}) ``` --- @@ -90,10 +288,48 @@ const slice2 = createSlice({ **Input** ([basic.input.js](transforms\createSliceBuilder__testfixtures__\basic.input.js)): ```js -const slice1 = createSlice({ - name: 'a', - initialState: {}, +import { + createAsyncThunk, + createEntityAdapter, + createSlice +} from '@reduxjs/toolkit' + +export const todoAdapter = createEntityAdapter() + +const todoInitialState = todoAdapter.getInitialState() + +const fetchCount = (amount = 1) => { + return new Promise((resolve) => + setTimeout(() => resolve({ data: amount }), 500) + ) +} + +export const incrementAsync = createAsyncThunk( + 'counter/fetchCount', + async (amount) => { + const response = await fetchCount(amount) + return response.data + } +) + +const { addOne } = todoAdapter + +const todoSlice = createSlice({ + name: 'todo', + initialState: todoInitialState, + reducers: { + deleteTodo: todoAdapter.removeOne + }, extraReducers: { + [incrementAsync.pending]: (state, action) => { + // stuff + }, + [incrementAsync.rejected]: todoAdapter.removeAll, + [incrementAsync.fulfilled](state, action) { + // stuff + }, + todoAdded: todoAdapter.addOne, + [todoAdded1a]: (state, action) => { // stuff }, @@ -110,76 +346,123 @@ const slice1 = createSlice({ todoAdded1f: (state, action) => { //stuff }, - }, -}); + [todoAdded1g]: addOne, + todoAdded1h: todoAdapter.addOne + } +}) -const slice2 = createSlice({ - name: 'b', - initialState: {}, +export const { deleteTodo } = todoSlice.actions + +const counterInitialState = { + value: 0, + status: 'idle' +} + +const counterSlice = createSlice({ + name: 'counter', + initialState: counterInitialState, extraReducers: { - [todoAdded2a]: (state, action) => { + [deleteTodo](state, action) { // stuff - }, - [todoAdded2b](state, action) { - // stuff - }, - [todoAdded2c]: function (state, action) { - // stuff - }, - }, -}); + } + } +}) ``` **Output** ([basic.output.js](transforms\createSliceBuilder__testfixtures__\basic.output.js)): ```js -const slice1 = createSlice({ - name: 'a', - initialState: {}, +import { + createAsyncThunk, + createEntityAdapter, + createSlice +} from '@reduxjs/toolkit' + +export const todoAdapter = createEntityAdapter() + +const todoInitialState = todoAdapter.getInitialState() + +const fetchCount = (amount = 1) => { + return new Promise((resolve) => + setTimeout(() => resolve({ data: amount }), 500) + ) +} + +export const incrementAsync = createAsyncThunk( + 'counter/fetchCount', + async (amount) => { + const response = await fetchCount(amount) + return response.data + } +) + +const { addOne } = todoAdapter + +const todoSlice = createSlice({ + name: 'todo', + initialState: todoInitialState, + + reducers: { + deleteTodo: todoAdapter.removeOne + }, extraReducers: (builder) => { + builder.addCase(incrementAsync.pending, (state, action) => { + // stuff + }) + + builder.addCase(incrementAsync.rejected, todoAdapter.removeAll) + + builder.addCase(incrementAsync.fulfilled, (state, action) => { + // stuff + }) + + builder.addCase(todoAdded, todoAdapter.addOne) + builder.addCase(todoAdded1a, (state, action) => { // stuff - }); + }) - builder.addCase(todoAdded1b, (state, action) => action.payload); + builder.addCase(todoAdded1b, (state, action) => action.payload) builder.addCase(todoAdded1c + 'test', (state, action) => { // stuff - }); + }) builder.addCase(todoAdded1d, (state, action) => { // stuff - }); + }) builder.addCase(todoAdded1e, (state, action) => { // stuff - }); + }) builder.addCase(todoAdded1f, (state, action) => { //stuff - }); - }, -}); + }) -const slice2 = createSlice({ - name: 'b', - initialState: {}, + builder.addCase(todoAdded1g, addOne) + builder.addCase(todoAdded1h, todoAdapter.addOne) + } +}) - extraReducers: (builder) => { - builder.addCase(todoAdded2a, (state, action) => { - // stuff - }); +export const { deleteTodo } = todoSlice.actions - builder.addCase(todoAdded2b, (state, action) => { - // stuff - }); +const counterInitialState = { + value: 0, + status: 'idle' +} - builder.addCase(todoAdded2c, (state, action) => { +const counterSlice = createSlice({ + name: 'counter', + initialState: counterInitialState, + + extraReducers: (builder) => { + builder.addCase(deleteTodo, (state, action) => { // stuff - }); - }, -}); + }) + } +}) ``` diff --git a/packages/rtk-codemods/transforms/createSliceReducerBuilder/README.md b/packages/rtk-codemods/transforms/createSliceReducerBuilder/README.md index cafb0c9d48..f6a959db00 100644 --- a/packages/rtk-codemods/transforms/createSliceReducerBuilder/README.md +++ b/packages/rtk-codemods/transforms/createSliceReducerBuilder/README.md @@ -26,7 +26,209 @@ node ./bin/cli.js createSliceReducerBuilder path/of/files/ or/some**/*glob.js ## Input / Output + +- [basic-ts](#basic-ts) +- [basic](#basic) - +## + +**basic-ts** + +**Input** ([basic-ts.input.ts](transforms\createSliceReducerBuilder__testfixtures__\basic-ts.input.ts)): + +```ts +import type { PayloadAction } from '@reduxjs/toolkit' +import { createEntityAdapter, createSlice, nanoid } from '@reduxjs/toolkit' + +function withPayload(): any { + throw new Error('Function not implemented.') +} + +export interface Todo { + id: string + title: string +} + +export const todoAdapter = createEntityAdapter() + +const todoSlice = createSlice({ + name: 'todo', + initialState: todoAdapter.getInitialState(), + reducers: { + property: () => {}, + method(state, action: PayloadAction) { + todoAdapter.addOne(state, action) + }, + identifier: todoAdapter.removeOne, + preparedProperty: { + prepare: (todo: Omit) => ({ + payload: { id: nanoid(), ...todo } + }), + reducer: () => {} + }, + preparedMethod: { + prepare(todo: Omit) { + return { payload: { id: nanoid(), ...todo } } + }, + reducer(state, action: PayloadAction) { + todoAdapter.addOne(state, action) + } + }, + preparedIdentifier: { + prepare: withPayload(), + reducer: todoAdapter.setMany + } + } +}) +``` + +**Output** ([basic-ts.output.ts](transforms\createSliceReducerBuilder__testfixtures__\basic-ts.output.ts)): + +```ts +import type { PayloadAction } from '@reduxjs/toolkit' +import { createEntityAdapter, createSlice, nanoid } from '@reduxjs/toolkit' + +function withPayload(): any { + throw new Error('Function not implemented.') +} + +export interface Todo { + id: string + title: string +} + +export const todoAdapter = createEntityAdapter() + +const todoSlice = createSlice({ + name: 'todo', + initialState: todoAdapter.getInitialState(), + + reducers: (create) => ({ + property: create.reducer(() => {}), + + method: create.reducer((state, action: PayloadAction) => { + todoAdapter.addOne(state, action) + }), + + identifier: create.reducer(todoAdapter.removeOne), + + preparedProperty: create.preparedReducer( + (todo: Omit) => ({ + payload: { id: nanoid(), ...todo } + }), + () => {} + ), + + preparedMethod: create.preparedReducer( + (todo: Omit) => { + return { payload: { id: nanoid(), ...todo } } + }, + (state, action: PayloadAction) => { + todoAdapter.addOne(state, action) + } + ), + + preparedIdentifier: create.preparedReducer( + withPayload(), + todoAdapter.setMany + ) + }) +}) +``` + +--- + +**basic** + +**Input** ([basic.input.js](transforms\createSliceReducerBuilder__testfixtures__\basic.input.js)): + +```js +import { createEntityAdapter, createSlice, nanoid } from '@reduxjs/toolkit' + +function withPayload() { + throw new Error('Function not implemented.') +} + +export const todoAdapter = createEntityAdapter() + +const todoSlice = createSlice({ + name: 'todo', + initialState: todoAdapter.getInitialState(), + reducers: { + property: () => {}, + method(state, action) { + todoAdapter.addOne(state, action) + }, + identifier: todoAdapter.removeOne, + preparedProperty: { + prepare: (todo) => ({ + payload: { id: nanoid(), ...todo } + }), + reducer: () => {} + }, + preparedMethod: { + prepare(todo) { + return { payload: { id: nanoid(), ...todo } } + }, + reducer(state, action) { + todoAdapter.addOne(state, action) + } + }, + preparedIdentifier: { + prepare: withPayload(), + reducer: todoAdapter.setMany + } + } +}) +``` + +**Output** ([basic.output.js](transforms\createSliceReducerBuilder__testfixtures__\basic.output.js)): + +```js +import { createEntityAdapter, createSlice, nanoid } from '@reduxjs/toolkit' + +function withPayload() { + throw new Error('Function not implemented.') +} + +export const todoAdapter = createEntityAdapter() + +const todoSlice = createSlice({ + name: 'todo', + initialState: todoAdapter.getInitialState(), + + reducers: (create) => ({ + property: create.reducer(() => {}), + + method: create.reducer((state, action) => { + todoAdapter.addOne(state, action) + }), + + identifier: create.reducer(todoAdapter.removeOne), + + preparedProperty: create.preparedReducer( + (todo) => ({ + payload: { id: nanoid(), ...todo } + }), + () => {} + ), + + preparedMethod: create.preparedReducer( + (todo) => { + return { payload: { id: nanoid(), ...todo } } + }, + (state, action) => { + todoAdapter.addOne(state, action) + } + ), + + preparedIdentifier: create.preparedReducer( + withPayload(), + todoAdapter.setMany + ) + }) +}) +``` +