Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 157 additions & 0 deletions docs/code-guidelines/controller-guidelines.md
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,163 @@ rootMessenger.subscribe('FooController:someEvent', () => {
});
```

## Define, but do not export, a name for the controller

Every controller has a name, which is not only used to namespace the controller's messenger actions and events, but also to namespace the controller's state data when composed with other controllers.

The name should be defined in a constant called `CONTROLLER_NAME` so that it can be easily changed if the need arises. (This variable was formerly called `controllerName`.) The name should be used to initialize the messenger, and should also be passed to the `BaseController` constructor.

The constant should be used to define actions and events. It may be exported from the file in which it is defined, but should not listed as an export of the package:

🚫 **The messenger namespace is not defined as a constant, but is repeated**

```typescript
export type FooControllerSomeCustomAction = {
type: 'FooController:someCustomAction';
handler: (bar: string) => void;
};

export type FooControllerAnotherCustomAction = {
type: 'FooController:anotherCustomAction';
handler: (baz: number) => void;
};

export type FooControllerActions =
| FooControllerSomeCustomAction
| FooControllerAnotherCustomAction;

export type FooControllerMessenger = Messenger<
'FooController',
FooControllerActions,
never
>;

export class FooController extends BaseController</* ... */ {
constructor(/* ... */) {
super({ name: 'FooController', /* ... */ })

// ...
}
}
```

🚫 **The messenger namespace is defined as a constant, but it is called `controllerName`**

```typescript
const controllerName = 'FooController';

export type FooControllerSomeCustomAction = {
type: `${typeof controllerName}:someCustomAction`;
handler: (bar: string) => void;
};

export type FooControllerAnotherCustomAction = {
type: `${typeof controllerName}:anotherCustomAction`;
handler: (baz: number) => void;
};

export type FooControllerActions =
| FooControllerSomeCustomAction
| FooControllerAnotherCustomAction;

export type FooControllerMessenger = Messenger<
typeof controllerName,
FooControllerActions,
never
>;

export class FooController extends BaseController</* ... */ {
constructor(/* ... */) {
super({ name: controllerName, /* ... */ })

// ...
}
}
```

🚫 **The messenger namespace is defined as a constant, but it is exported from the package**

```typescript
/* packages/foo-controller/src/foo-controller.ts */

export const CONTROLLER_NAME = 'FooController';

export type FooControllerSomeCustomAction = {
type: `${typeof CONTROLLER_NAME}:someCustomAction`;
handler: (bar: string) => void;
};

export type FooControllerAnotherCustomAction = {
type: `${typeof CONTROLLER_NAME}:anotherCustomAction`;
handler: (baz: number) => void;
};

export type FooControllerActions =
| FooControllerSomeCustomAction
| FooControllerAnotherCustomAction;

export type FooControllerMessenger = Messenger<
typeof CONTROLLER_NAME,
FooControllerActions,
never
>;

export class FooController extends BaseController</* ... */ {
constructor(/* ... */) {
super({ name: CONTROLLER_NAME, /* ... */ })

// ...
}
}

/* packages/foo-controller/src/index.ts */

export {
CONTROLLER_NAME,
FooController
} from './foo-controller';
```

✅ **The messenger namespace is defined as a constant, and it is kept internal instead of being exported**

```typescript
/* packages/foo-controller/src/foo-controller.ts */

const CONTROLLER_NAME = 'FooController';

export type FooControllerSomeCustomAction = {
type: `${CONTROLLER_NAME}:someCustomAction`;
handler: (bar: string) => void;
};

export type FooControllerAnotherCustomAction = {
type: `${CONTROLLER_NAME}:anotherCustomAction`;
handler: (baz: number) => void;
};

export type FooControllerActions =
| FooControllerSomeCustomAction
| FooControllerAnotherCustomAction;

export type FooControllerMessenger = Messenger<
CONTROLLER_NAME,
FooControllerActions,
never
>;

export class FooController extends BaseController</* ... */ {
constructor(/* ... */) {
super({ name: CONTROLLER_NAME, /* ... */ })

// ...
}
}

/* packages/foo-controller/src/index.ts */

export { FooController } from './foo-controller';
```

## Expose controller methods through messenger in bulk

Exposing controller methods through the messenger can be tedious. An action type must be created for each method, each action type must be added to the messenger type, and each action must be registered through the messenger. This creates a lot of boilerplate that must be maintained.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import type { SampleGasPricesServiceFetchGasPricesAction } from './sample-gas-pr
* controller's actions and events and to namespace the controller's state data
* when composed with other controllers.
*/
export const controllerName = 'SampleGasPricesController';
const CONTROLLER_NAME = 'SampleGasPricesController';

// === STATE ===

Expand Down Expand Up @@ -94,7 +94,7 @@ const MESSENGER_EXPOSED_METHODS = ['updateGasPrices'] as const;
* Retrieves the state of the {@link SampleGasPricesController}.
*/
export type SampleGasPricesControllerGetStateAction = ControllerGetStateAction<
typeof controllerName,
typeof CONTROLLER_NAME,
SampleGasPricesControllerState
>;

Expand All @@ -117,7 +117,7 @@ type AllowedActions =
*/
export type SampleGasPricesControllerStateChangeEvent =
ControllerStateChangeEvent<
typeof controllerName,
typeof CONTROLLER_NAME,
SampleGasPricesControllerState
>;

Expand All @@ -138,7 +138,7 @@ type AllowedEvents = NetworkControllerStateChangeEvent;
* {@link SampleGasPricesController}.
*/
export type SampleGasPricesControllerMessenger = Messenger<
typeof controllerName,
typeof CONTROLLER_NAME,
SampleGasPricesControllerActions | AllowedActions,
SampleGasPricesControllerEvents | AllowedEvents
>;
Expand Down Expand Up @@ -219,7 +219,7 @@ export type SampleGasPricesControllerMessenger = Messenger<
* ```
*/
export class SampleGasPricesController extends BaseController<
typeof controllerName,
typeof CONTROLLER_NAME,
SampleGasPricesControllerState,
SampleGasPricesControllerMessenger
> {
Expand All @@ -246,7 +246,7 @@ export class SampleGasPricesController extends BaseController<
super({
messenger,
metadata: gasPricesControllerMetadata,
name: controllerName,
name: CONTROLLER_NAME,
state: {
...getDefaultSampleGasPricesControllerState(),
...state,
Expand Down
12 changes: 6 additions & 6 deletions packages/sample-controllers/src/sample-petnames-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import type { SamplePetnamesControllerMethodActions } from './sample-petnames-co
* controller's actions and events and to namespace the controller's state data
* when composed with other controllers.
*/
export const controllerName = 'SamplePetnamesController';
const CONTROLLER_NAME = 'SamplePetnamesController';

// === STATE ===

Expand Down Expand Up @@ -70,7 +70,7 @@ const MESSENGER_EXPOSED_METHODS = ['assignPetname'] as const;
* Retrieves the state of the {@link SamplePetnamesController}.
*/
export type SamplePetnamesControllerGetStateAction = ControllerGetStateAction<
typeof controllerName,
typeof CONTROLLER_NAME,
SamplePetnamesControllerState
>;

Expand All @@ -91,7 +91,7 @@ type AllowedActions = never;
*/
export type SamplePetnamesControllerStateChangeEvent =
ControllerStateChangeEvent<
typeof controllerName,
typeof CONTROLLER_NAME,
SamplePetnamesControllerState
>;

Expand All @@ -112,7 +112,7 @@ type AllowedEvents = never;
* {@link SamplePetnamesController}.
*/
export type SamplePetnamesControllerMessenger = Messenger<
typeof controllerName,
typeof CONTROLLER_NAME,
SamplePetnamesControllerActions | AllowedActions,
SamplePetnamesControllerEvents | AllowedEvents
>;
Expand Down Expand Up @@ -167,7 +167,7 @@ export type SamplePetnamesControllerMessenger = Messenger<
* ```
*/
export class SamplePetnamesController extends BaseController<
typeof controllerName,
typeof CONTROLLER_NAME,
SamplePetnamesControllerState,
SamplePetnamesControllerMessenger
> {
Expand All @@ -189,7 +189,7 @@ export class SamplePetnamesController extends BaseController<
super({
messenger,
metadata: samplePetnamesControllerMetadata,
name: controllerName,
name: CONTROLLER_NAME,
state: {
...getDefaultPetnamesControllerState(),
...state,
Expand Down
Loading