Skip to content

Commit

Permalink
feat(devtools middleware) add automatic action name finding
Browse files Browse the repository at this point in the history
  • Loading branch information
alimertcakar committed Jan 30, 2025
1 parent bc3e94e commit 6d5b4ab
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 2 deletions.
18 changes: 16 additions & 2 deletions src/middleware/devtools.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type {} from '@redux-devtools/extension'

import type {
StateCreator,
StoreApi,
Expand Down Expand Up @@ -72,6 +73,7 @@ export interface DevtoolsOptions extends Config {
name?: string
enabled?: boolean
anonymousActionType?: string
inferActionName?: boolean
store?: string
}

Expand Down Expand Up @@ -109,6 +111,13 @@ type ConnectionInformation = {
connection: Connection
stores: Record<StoreName, StoreInformation>
}
const findCallerName = (stack: string) => {
const traceLines = stack?.split?.('\n') ?? []
const isBlinkStackTrace = stack.startsWith('Error')
return isBlinkStackTrace
? traceLines?.[2]?.trim().split(' ')[1]
: traceLines?.[1]?.trim().split('@')[0]
}
const trackedConnections: Map<ConnectionName, ConnectionInformation> = new Map()

const getTrackedConnectionState = (
Expand Down Expand Up @@ -149,7 +158,8 @@ const extractConnectionInformation = (
const devtoolsImpl: DevtoolsImpl =
(fn, devtoolsOptions = {}) =>
(set, get, api) => {
const { enabled, anonymousActionType, store, ...options } = devtoolsOptions
const { enabled, anonymousActionType, inferActionName, store, ...options } =
devtoolsOptions

type S = ReturnType<typeof fn> & {
[store: string]: ReturnType<typeof fn>
Expand Down Expand Up @@ -178,9 +188,13 @@ const devtoolsImpl: DevtoolsImpl =
;(api.setState as any) = ((state, replace, nameOrAction: Action) => {
const r = set(state, replace as any)
if (!isRecording) return r
let defaultActionName = anonymousActionType
if (inferActionName) {
defaultActionName = findCallerName(new Error().stack ?? '')
}
const action: { type: string } =
nameOrAction === undefined
? { type: anonymousActionType || 'anonymous' }
? { type: defaultActionName || 'anonymous' }
: typeof nameOrAction === 'string'
? { type: nameOrAction }
: nameOrAction
Expand Down
30 changes: 30 additions & 0 deletions tests/devtools.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,36 @@ describe('When state changes...', () => {
})
})

describe('When state changes with automatic setter inferring...', () => {
it("sends { type: setStateName || 'setCount`, ...rest } as the action with current state", async () => {
const options = {
name: 'testOptionsName',
enabled: true,
inferActionName: true,
}

const api = createStore(
devtools(
(set) => ({
count: 0,
setCount: (newCount: number) => {
set({ count: newCount })
},
}),
options,
),
)
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
api.getState().setCount(10)
const [connection] = getNamedConnectionApis(options.name)
expect(connection.send).toHaveBeenLastCalledWith(
{ type: 'Object.setCount' },
{ count: 10, setCount: expect.any(Function) },
)
})
})

describe('when it receives a message of type...', () => {
describe('ACTION...', () => {
it('does nothing', async () => {
Expand Down

0 comments on commit 6d5b4ab

Please sign in to comment.