Skip to content

Commit 83560cc

Browse files
committed
refactor: extract actions to a separate file
1 parent 60b7241 commit 83560cc

File tree

5 files changed

+393
-82
lines changed

5 files changed

+393
-82
lines changed

packages/base-controller/src/BaseControllerV2.test.ts

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1145,4 +1145,184 @@ describe('getPersistentState', () => {
11451145
expect(visitorController.state.visitors).toHaveLength(0);
11461146
});
11471147
});
1148+
1149+
describe('registerActionHandlers', () => {
1150+
type TestControllerActions =
1151+
| {
1152+
type: 'TestController:testMethod';
1153+
handler: () => string;
1154+
}
1155+
| { type: 'TestController:method1'; handler: () => string }
1156+
| { type: 'TestController:method2'; handler: () => string }
1157+
| { type: 'TestController:getInstanceValue'; handler: () => string };
1158+
1159+
type TestControllerMessenger = RestrictedMessenger<
1160+
'TestController',
1161+
TestControllerActions,
1162+
never,
1163+
never,
1164+
never
1165+
>;
1166+
1167+
/**
1168+
* Factory function to create a test controller with configurable action handler registration
1169+
*
1170+
* @param options - Configuration options for the test controller
1171+
* @param options.methodsToRegister - Array of method names to register as action handlers
1172+
* @param options.excludedMethods - Optional array of method names to exclude from registration
1173+
* @param options.exceptions - Optional map of method names to custom handlers
1174+
* @param options.instanceValue - Optional custom value for the controller instance
1175+
* @returns Object containing the messenger and controller instances
1176+
*/
1177+
function createTestController(options: {
1178+
methodsToRegister: readonly string[];
1179+
excludedMethods?: readonly string[];
1180+
exceptions?: Record<string, (...args: unknown[]) => unknown>;
1181+
instanceValue?: string;
1182+
}) {
1183+
const {
1184+
methodsToRegister,
1185+
excludedMethods = [],
1186+
exceptions = {},
1187+
instanceValue = 'controller instance',
1188+
} = options;
1189+
1190+
class TestController extends BaseController<
1191+
'TestController',
1192+
CountControllerState,
1193+
TestControllerMessenger
1194+
> {
1195+
private readonly instanceValue = instanceValue;
1196+
1197+
constructor(messenger: TestControllerMessenger) {
1198+
super({
1199+
messenger,
1200+
name: 'TestController',
1201+
state: { count: 0 },
1202+
metadata: countControllerStateMetadata,
1203+
});
1204+
this.registerActionHandlers(
1205+
methodsToRegister as readonly (keyof this & string)[],
1206+
excludedMethods,
1207+
exceptions as Partial<
1208+
Record<keyof this & string, (...args: unknown[]) => unknown>
1209+
>,
1210+
);
1211+
}
1212+
1213+
testMethod() {
1214+
return 'test result';
1215+
}
1216+
1217+
method1() {
1218+
return 'method1 result';
1219+
}
1220+
1221+
method2() {
1222+
return 'method2 result';
1223+
}
1224+
1225+
getInstanceValue() {
1226+
return this.instanceValue;
1227+
}
1228+
}
1229+
1230+
const messenger = new Messenger<TestControllerActions, never>();
1231+
const controller = new TestController(
1232+
messenger.getRestricted({
1233+
name: 'TestController',
1234+
allowedActions: [],
1235+
allowedEvents: [],
1236+
}),
1237+
);
1238+
1239+
return { messenger, controller };
1240+
}
1241+
1242+
it('should register action handlers for specified methods using the simplified API', () => {
1243+
const { messenger } = createTestController({
1244+
methodsToRegister: ['testMethod', 'method1'],
1245+
});
1246+
1247+
const testResult = messenger.call('TestController:testMethod');
1248+
expect(testResult).toBe('test result');
1249+
1250+
const method1Result = messenger.call('TestController:method1');
1251+
expect(method1Result).toBe('method1 result');
1252+
});
1253+
1254+
it('should register action handlers with exclusions and exceptions', () => {
1255+
const customMethod1 = () => 'custom method1 result';
1256+
1257+
const { messenger } = createTestController({
1258+
methodsToRegister: ['method1', 'method2'],
1259+
excludedMethods: ['method2'],
1260+
exceptions: { method1: customMethod1 },
1261+
});
1262+
1263+
// method1 should use the custom handler
1264+
const result1 = messenger.call('TestController:method1');
1265+
expect(result1).toBe('custom method1 result');
1266+
1267+
// method2 should not be registered due to exclusion
1268+
expect(() => {
1269+
messenger.call('TestController:method2');
1270+
}).toThrow(
1271+
'A handler for TestController:method2 has not been registered',
1272+
);
1273+
});
1274+
1275+
it('should properly bind methods to the controller instance', () => {
1276+
const { messenger } = createTestController({
1277+
methodsToRegister: ['getInstanceValue'],
1278+
instanceValue: 'custom instance value',
1279+
});
1280+
1281+
// Verify the method is properly bound to the controller instance
1282+
const result = messenger.call('TestController:getInstanceValue');
1283+
expect(result).toBe('custom instance value');
1284+
});
1285+
1286+
it('should handle empty method registration', () => {
1287+
const { messenger } = createTestController({
1288+
methodsToRegister: [],
1289+
});
1290+
1291+
// None of the methods should be registered
1292+
expect(() => {
1293+
messenger.call('TestController:testMethod');
1294+
}).toThrow(
1295+
'A handler for TestController:testMethod has not been registered',
1296+
);
1297+
1298+
expect(() => {
1299+
messenger.call('TestController:method1');
1300+
}).toThrow(
1301+
'A handler for TestController:method1 has not been registered',
1302+
);
1303+
});
1304+
1305+
it('should handle multiple exclusions', () => {
1306+
const { messenger } = createTestController({
1307+
methodsToRegister: ['testMethod', 'method1', 'method2'],
1308+
excludedMethods: ['method1', 'method2'],
1309+
});
1310+
1311+
// Only testMethod should be registered
1312+
const testResult = messenger.call('TestController:testMethod');
1313+
expect(testResult).toBe('test result');
1314+
1315+
expect(() => {
1316+
messenger.call('TestController:method1');
1317+
}).toThrow(
1318+
'A handler for TestController:method1 has not been registered',
1319+
);
1320+
1321+
expect(() => {
1322+
messenger.call('TestController:method2');
1323+
}).toThrow(
1324+
'A handler for TestController:method2 has not been registered',
1325+
);
1326+
});
1327+
});
11481328
});

packages/base-controller/src/BaseControllerV2.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { enablePatches, produceWithPatches, applyPatches, freeze } from 'immer';
33
import type { Draft, Patch } from 'immer';
44

55
import type { ActionConstraint, EventConstraint } from './Messenger';
6+
import { registerMethodActionHandlers } from './Messenger';
67
import type {
78
RestrictedMessenger,
89
RestrictedMessengerConstraint,
@@ -313,6 +314,32 @@ export class BaseController<
313314
protected destroy() {
314315
this.messagingSystem.clearEventSubscriptions(`${this.name}:stateChange`);
315316
}
317+
318+
/**
319+
* Registers action handlers for a list of methods on this controller.
320+
*
321+
* This is a convenience method that automatically provides the controller instance
322+
* and messaging system to the registerMethodActionHandlers function.
323+
*
324+
* @param methodNames - The names of the methods to register as action handlers
325+
* @param excludedMethods - Optional list of method names to exclude from registration
326+
* @param exceptions - Optional map of method names to custom handlers
327+
*/
328+
protected registerActionHandlers<MethodNames extends keyof this & string>(
329+
methodNames: readonly MethodNames[],
330+
excludedMethods: readonly string[] = ['constructor', 'messagingSystem'],
331+
exceptions: Partial<
332+
Record<MethodNames, (...args: unknown[]) => unknown>
333+
> = {},
334+
): void {
335+
registerMethodActionHandlers(
336+
this,
337+
this.messagingSystem,
338+
methodNames,
339+
excludedMethods,
340+
exceptions,
341+
);
342+
}
316343
}
317344

318345
/**

packages/network-controller/src/NetworkController.ts

Lines changed: 2 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,7 @@ import type {
44
MessengerMethodActions,
55
RestrictedMessenger,
66
} from '@metamask/base-controller';
7-
import {
8-
BaseController,
9-
registerMethodActionHandlers,
10-
} from '@metamask/base-controller';
7+
import { BaseController } from '@metamask/base-controller';
118
import type { Partialize } from '@metamask/controller-utils';
129
import {
1310
InfuraNetworkType,
@@ -519,72 +516,6 @@ export type NetworkControllerGetEthQueryAction = {
519516
handler: () => EthQuery | undefined;
520517
};
521518

522-
export type NetworkControllerGetNetworkClientByIdAction = {
523-
type: `NetworkController:getNetworkClientById`;
524-
handler: NetworkController['getNetworkClientById'];
525-
};
526-
527-
export type NetworkControllerGetSelectedNetworkClientAction = {
528-
type: `NetworkController:getSelectedNetworkClient`;
529-
handler: NetworkController['getSelectedNetworkClient'];
530-
};
531-
532-
export type NetworkControllerGetSelectedChainIdAction = {
533-
type: 'NetworkController:getSelectedChainId';
534-
handler: NetworkController['getSelectedChainId'];
535-
};
536-
537-
export type NetworkControllerGetEIP1559CompatibilityAction = {
538-
type: `NetworkController:getEIP1559Compatibility`;
539-
handler: NetworkController['getEIP1559Compatibility'];
540-
};
541-
542-
export type NetworkControllerFindNetworkClientIdByChainIdAction = {
543-
type: `NetworkController:findNetworkClientIdByChainId`;
544-
handler: NetworkController['findNetworkClientIdByChainId'];
545-
};
546-
547-
/**
548-
* Change the currently selected network to the given built-in network type.
549-
*
550-
* @deprecated This action has been replaced by `setActiveNetwork`, and will be
551-
* removed in a future release.
552-
*/
553-
export type NetworkControllerSetProviderTypeAction = {
554-
type: `NetworkController:setProviderType`;
555-
handler: NetworkController['setProviderType'];
556-
};
557-
558-
export type NetworkControllerSetActiveNetworkAction = {
559-
type: `NetworkController:setActiveNetwork`;
560-
handler: NetworkController['setActiveNetwork'];
561-
};
562-
563-
export type NetworkControllerGetNetworkConfigurationByChainId = {
564-
type: `NetworkController:getNetworkConfigurationByChainId`;
565-
handler: NetworkController['getNetworkConfigurationByChainId'];
566-
};
567-
568-
export type NetworkControllerGetNetworkConfigurationByNetworkClientId = {
569-
type: `NetworkController:getNetworkConfigurationByNetworkClientId`;
570-
handler: NetworkController['getNetworkConfigurationByNetworkClientId'];
571-
};
572-
573-
export type NetworkControllerAddNetworkAction = {
574-
type: 'NetworkController:addNetwork';
575-
handler: NetworkController['addNetwork'];
576-
};
577-
578-
export type NetworkControllerRemoveNetworkAction = {
579-
type: 'NetworkController:removeNetwork';
580-
handler: NetworkController['removeNetwork'];
581-
};
582-
583-
export type NetworkControllerUpdateNetworkAction = {
584-
type: 'NetworkController:updateNetwork';
585-
handler: NetworkController['updateNetwork'];
586-
};
587-
588519
// Define the methods we want to expose via the messenger
589520
const MESSENGER_EXPOSED_METHODS = [
590521
'getNetworkClientById',
@@ -1242,11 +1173,7 @@ export class NetworkController extends BaseController<
12421173
this.state.networkConfigurationsByChainId,
12431174
);
12441175

1245-
registerMethodActionHandlers(
1246-
this,
1247-
this.messagingSystem,
1248-
MESSENGER_EXPOSED_METHODS,
1249-
);
1176+
this.registerActionHandlers(MESSENGER_EXPOSED_METHODS);
12501177
}
12511178

12521179
/**

packages/network-controller/src/index.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,14 @@ export type {
2222
NetworkControllerEvents,
2323
NetworkControllerGetStateAction,
2424
NetworkControllerGetEthQueryAction,
25+
NetworkControllerActions,
26+
NetworkControllerMessenger,
27+
NetworkControllerOptions,
28+
NetworkControllerRpcEndpointUnavailableEvent,
29+
NetworkControllerRpcEndpointDegradedEvent,
30+
NetworkControllerRpcEndpointRequestRetriedEvent,
31+
} from './NetworkController';
32+
export type {
2533
NetworkControllerGetNetworkClientByIdAction,
2634
NetworkControllerGetSelectedNetworkClientAction,
2735
NetworkControllerGetSelectedChainIdAction,
@@ -33,13 +41,7 @@ export type {
3341
NetworkControllerRemoveNetworkAction,
3442
NetworkControllerUpdateNetworkAction,
3543
NetworkControllerGetNetworkConfigurationByNetworkClientId,
36-
NetworkControllerActions,
37-
NetworkControllerMessenger,
38-
NetworkControllerOptions,
39-
NetworkControllerRpcEndpointUnavailableEvent,
40-
NetworkControllerRpcEndpointDegradedEvent,
41-
NetworkControllerRpcEndpointRequestRetriedEvent,
42-
} from './NetworkController';
44+
} from './network-controller-method-action-types';
4345
export {
4446
getDefaultNetworkControllerState,
4547
selectAvailableNetworkClientIds,

0 commit comments

Comments
 (0)