Skip to content

Commit

Permalink
chore: refactor getAction (#2429)
Browse files Browse the repository at this point in the history
* chore: refactor getAction

* Create grumpy-cycles-drop.md
  • Loading branch information
jxom committed Jun 20, 2024
1 parent f9d4ead commit 3781bbb
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 15 deletions.
5 changes: 5 additions & 0 deletions .changeset/grumpy-cycles-drop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"viem": patch
---

Fixed an issue where `getAction` would ignore nullish return values from a synchronous Client Action.
10 changes: 10 additions & 0 deletions src/utils/getAction.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@ test('uses client action', async () => {
expect(clientSpy).toBeCalledWith({})
})

test('nullish return value', async () => {
const foo = () => null
const foo_2 = () => true
const client_2 = client.extend(() => ({
foo,
}))
const result = getAction(client_2, foo_2, 'foo')({})
expect(result).toEqual(null)
})

test('e2e', async () => {
const client_2 = client.extend(() => ({
async call() {
Expand Down
46 changes: 31 additions & 15 deletions src/utils/getAction.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import type { Client } from '../clients/createClient.js'
import type { PublicActions } from '../clients/decorators/public.js'
import type { WalletActions } from '../clients/decorators/wallet.js'
import type { Transport } from '../clients/transports/createTransport.js'
import type { Account } from '../types/account.js'
import type { Chain } from '../types/chain.js'
import type { RpcSchema } from '../types/eip1193.js'

/**
* Retrieves and returns an action from the client (if exists), and falls
Expand All @@ -7,20 +13,30 @@ import type { Client } from '../clients/createClient.js'
* Useful for extracting overridden actions from a client (ie. if a consumer
* wants to override the `sendTransaction` implementation).
*/
export function getAction<params extends {}, returnType extends {}>(
client: Client,
action: (_: any, params: params) => returnType,
// Some minifiers drop `Function.prototype.name` or can change function
// names so that getting the name by reflection through `action.name` will
// not work.
name: string,
) {
type DecoratedClient = Client & {
[key: string]: (params: params) => returnType
}
export function getAction<
transport extends Transport,
chain extends Chain | undefined,
account extends Account | undefined,
rpcSchema extends RpcSchema | undefined,
extended extends { [key: string]: unknown },
client extends Client<transport, chain, account, rpcSchema, extended>,
parameters,
returnType,
>(
client: client,
actionFn: (_: any, parameters: parameters) => returnType,
// Some minifiers drop `Function.prototype.name`, or replace it with short letters,
// meaning that `actionFn.name` will not always work. For that case, the consumer
// needs to pass the name explicitly.
name: keyof PublicActions | keyof WalletActions | (string & {}),
): (parameters: parameters) => returnType {
const action_implicit = client[actionFn.name]
if (typeof action_implicit === 'function')
return action_implicit as (params: parameters) => returnType

return (params: params): returnType =>
(client as DecoratedClient)[action.name]?.(params) ??
(client as DecoratedClient)[name]?.(params) ??
action(client, params)
const action_explicit = client[name]
if (typeof action_explicit === 'function')
return action_explicit as (params: parameters) => returnType

return (params) => actionFn(client, params)
}

0 comments on commit 3781bbb

Please sign in to comment.