Skip to content

Commit

Permalink
Post-rebase fixup
Browse files Browse the repository at this point in the history
  • Loading branch information
rekmarks committed Apr 15, 2021
1 parent ae73f31 commit 0db3170
Show file tree
Hide file tree
Showing 18 changed files with 694 additions and 867 deletions.
126 changes: 97 additions & 29 deletions src/BaseControllerV2.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
import type { Draft, Patch } from 'immer';
import sinon from 'sinon';

import { BaseController, getAnonymizedState, getPersistentState } from './BaseControllerV2';
import { ControllerMessenger, RestrictedControllerMessenger } from './ControllerMessenger';
import {
BaseController,
getAnonymizedState,
getPersistentState,
} from './BaseControllerV2';
import {
ControllerMessenger,
RestrictedControllerMessenger,
} from './ControllerMessenger';

type CountControllerState = {
count: number;
Expand All @@ -20,8 +27,15 @@ const countControllerStateMetadata = {
},
};

class CountController extends BaseController<'CountController', CountControllerState> {
update(callback: (state: Draft<CountControllerState>) => void | CountControllerState) {
class CountController extends BaseController<
'CountController',
CountControllerState
> {
update(
callback: (
state: Draft<CountControllerState>,
) => void | CountControllerState,
) {
super.update(callback);
}

Expand All @@ -32,7 +46,10 @@ class CountController extends BaseController<'CountController', CountControllerS

describe('BaseController', () => {
it('should set initial state', () => {
const controllerMessenger = new ControllerMessenger<never, CountControllerEvent>();
const controllerMessenger = new ControllerMessenger<
never,
CountControllerEvent
>();
const restrictedControllerMessenger = controllerMessenger.getRestricted({
name: 'CountController',
allowedActions: [],
Expand All @@ -49,7 +66,10 @@ describe('BaseController', () => {
});

it('should set initial schema', () => {
const controllerMessenger = new ControllerMessenger<never, CountControllerEvent>();
const controllerMessenger = new ControllerMessenger<
never,
CountControllerEvent
>();
const restrictedControllerMessenger = controllerMessenger.getRestricted({
name: 'CountController',
allowedActions: [],
Expand All @@ -62,11 +82,14 @@ describe('BaseController', () => {
metadata: countControllerStateMetadata,
});

expect(controller.metadata).toStrictEqual(CountControllerStateMetadata);
expect(controller.metadata).toStrictEqual(countControllerStateMetadata);
});

it('should not allow mutating state directly', () => {
const controllerMessenger = new ControllerMessenger<never, CountControllerEvent>();
const controllerMessenger = new ControllerMessenger<
never,
CountControllerEvent
>();
const restrictedControllerMessenger = controllerMessenger.getRestricted({
name: 'CountController',
allowedActions: [],
Expand All @@ -87,7 +110,10 @@ describe('BaseController', () => {
});

it('should allow updating state by modifying draft', () => {
const controllerMessenger = new ControllerMessenger<never, CountControllerEvent>();
const controllerMessenger = new ControllerMessenger<
never,
CountControllerEvent
>();
const restrictedControllerMessenger = controllerMessenger.getRestricted({
name: 'CountController',
allowedActions: [],
Expand All @@ -108,7 +134,10 @@ describe('BaseController', () => {
});

it('should allow updating state by return a value', () => {
const controllerMessenger = new ControllerMessenger<never, CountControllerEvent>();
const controllerMessenger = new ControllerMessenger<
never,
CountControllerEvent
>();
const restrictedControllerMessenger = controllerMessenger.getRestricted({
name: 'CountController',
allowedActions: [],
Expand All @@ -129,7 +158,10 @@ describe('BaseController', () => {
});

it('should throw an error if update callback modifies draft and returns value', () => {
const controllerMessenger = new ControllerMessenger<never, CountControllerEvent>();
const controllerMessenger = new ControllerMessenger<
never,
CountControllerEvent
>();
const restrictedControllerMessenger = controllerMessenger.getRestricted({
name: 'CountController',
allowedActions: [],
Expand All @@ -153,7 +185,10 @@ describe('BaseController', () => {
});

it('should inform subscribers of state changes', () => {
const controllerMessenger = new ControllerMessenger<never, CountControllerEvent>();
const controllerMessenger = new ControllerMessenger<
never,
CountControllerEvent
>();
const restrictedControllerMessenger = controllerMessenger.getRestricted({
name: 'CountController',
allowedActions: [],
Expand Down Expand Up @@ -187,7 +222,10 @@ describe('BaseController', () => {
});

it('should inform a subscriber of each state change once even after multiple subscriptions', () => {
const controllerMessenger = new ControllerMessenger<never, CountControllerEvent>();
const controllerMessenger = new ControllerMessenger<
never,
CountControllerEvent
>();
const restrictedControllerMessenger = controllerMessenger.getRestricted({
name: 'CountController',
allowedActions: [],
Expand Down Expand Up @@ -216,7 +254,10 @@ describe('BaseController', () => {
});

it('should no longer inform a subscriber about state changes after unsubscribing', () => {
const controllerMessenger = new ControllerMessenger<never, CountControllerEvent>();
const controllerMessenger = new ControllerMessenger<
never,
CountControllerEvent
>();
const restrictedControllerMessenger = controllerMessenger.getRestricted({
name: 'CountController',
allowedActions: [],
Expand All @@ -240,7 +281,10 @@ describe('BaseController', () => {
});

it('should no longer inform a subscriber about state changes after unsubscribing once, even if they subscribed many times', () => {
const controllerMessenger = new ControllerMessenger<never, CountControllerEvent>();
const controllerMessenger = new ControllerMessenger<
never,
CountControllerEvent
>();
const restrictedControllerMessenger = controllerMessenger.getRestricted({
name: 'CountController',
allowedActions: [],
Expand All @@ -265,7 +309,10 @@ describe('BaseController', () => {
});

it('should throw when unsubscribing listener who was never subscribed', () => {
const controllerMessenger = new ControllerMessenger<never, CountControllerEvent>();
const controllerMessenger = new ControllerMessenger<
never,
CountControllerEvent
>();
const restrictedControllerMessenger = controllerMessenger.getRestricted({
name: 'CountController',
allowedActions: [],
Expand All @@ -287,7 +334,10 @@ describe('BaseController', () => {
});

it('should no longer update subscribers after being destroyed', () => {
const controllerMessenger = new ControllerMessenger<never, CountControllerEvent>();
const controllerMessenger = new ControllerMessenger<
never,
CountControllerEvent
>();
const restrictedControllerMessenger = controllerMessenger.getRestricted({
name: 'CountController',
allowedActions: [],
Expand Down Expand Up @@ -630,7 +680,10 @@ describe('getPersistentState', () => {
},
};

class VisitorController extends BaseController<'VisitorController', VisitorControllerState> {
class VisitorController extends BaseController<
'VisitorController',
VisitorControllerState
> {
constructor(
messagingSystem: RestrictedControllerMessenger<
'VisitorController',
Expand All @@ -646,7 +699,10 @@ describe('getPersistentState', () => {
name: 'VisitorController',
state: { visitors: [] },
});
messagingSystem.registerActionHandler('VisitorController:clear', this.clear);
messagingSystem.registerActionHandler(
'VisitorController:clear',
this.clear,
);
}

clear = () => {
Expand Down Expand Up @@ -704,8 +760,14 @@ describe('getPersistentState', () => {
name: 'VisitorOverflowController',
state: { maxVisitors: 5 },
});
messagingSystem.registerActionHandler('VisitorOverflowController:updateMax', this.updateMax);
messagingSystem.subscribe('VisitorController:stateChange', this.onVisit);
messagingSystem.registerActionHandler(
'VisitorOverflowController:updateMax',
this.updateMax,
);
messagingSystem.subscribe(
'VisitorController:stateChange',
this.onVisit,
);
}

onVisit = ({ visitors }: VisitorControllerState) => {
Expand Down Expand Up @@ -735,20 +797,26 @@ describe('getPersistentState', () => {
allowedActions: [],
allowedEvents: [],
});
const visitorController = new VisitorController(visitorControllerMessenger);
const visitorOverflowControllerMessenger = controllerMessenger.getRestricted({
name: 'VisitorOverflowController',
allowedActions: ['VisitorController:clear'],
allowedEvents: ['VisitorController:stateChange'],
});
const visitorOverflowController = new VisitorOverflowController(visitorOverflowControllerMessenger);
const visitorController = new VisitorController(
visitorControllerMessenger,
);
const visitorOverflowControllerMessenger = controllerMessenger.getRestricted(
{
name: 'VisitorOverflowController',
allowedActions: ['VisitorController:clear'],
allowedEvents: ['VisitorController:stateChange'],
},
);
const visitorOverflowController = new VisitorOverflowController(
visitorOverflowControllerMessenger,
);

controllerMessenger.call('VisitorOverflowController:updateMax', 2);
visitorController.addVisitor('A');
visitorController.addVisitor('B');
visitorController.addVisitor('C'); // this should trigger an overflow

expect(visitorOverflowController.state.maxVisitors).toEqual(2);
expect(visitorOverflowController.state.maxVisitors).toStrictEqual(2);
expect(visitorController.state.visitors).toHaveLength(0);
});
});
Expand Down
44 changes: 37 additions & 7 deletions src/BaseControllerV2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import { enablePatches, produceWithPatches } from 'immer';
// eslint-disable-next-line no-duplicate-imports
import type { Draft, Patch } from 'immer';

import type { RestrictedControllerMessenger, Namespaced } from './ControllerMessenger';
import type {
RestrictedControllerMessenger,
Namespaced,
} from './ControllerMessenger';

enablePatches();

Expand Down Expand Up @@ -94,9 +97,18 @@ export interface StatePropertyMetadata<T> {
anonymous: boolean | StateDeriver<T>;
}

type Json = null | boolean | number | string | Json[] | { [prop: string]: Json };
type Json =
| null
| boolean
| number
| string
| Json[]
| { [prop: string]: Json };

type StateChangeEvent<N extends string, S, E> = E extends { type: `${N}:stateChange`; payload: [S, Patch[]] }
type StateChangeEvent<N extends string, S, E> = E extends {
type: `${N}:stateChange`;
payload: [S, Patch[]];
}
? E
: never;

Expand All @@ -109,7 +121,13 @@ export class BaseController<
> {
private internalState: IsJsonable<S>;

protected messagingSystem: RestrictedControllerMessenger<N, any, StateChangeEvent<N, S, any>, string, string>;
protected messagingSystem: RestrictedControllerMessenger<
N,
any,
StateChangeEvent<N, S, any>,
string,
string
>;

private name: N;

Expand All @@ -131,7 +149,13 @@ export class BaseController<
name,
state,
}: {
messenger: RestrictedControllerMessenger<N, any, StateChangeEvent<N, S, any>, string, string>;
messenger: RestrictedControllerMessenger<
N,
any,
StateChangeEvent<N, S, any>,
string,
string
>;
metadata: StateMetadata<S>;
name: N;
state: IsJsonable<S>;
Expand Down Expand Up @@ -174,7 +198,11 @@ export class BaseController<
callback,
);
this.internalState = nextState as IsJsonable<S>;
this.messagingSystem.publish(`${this.name}:stateChange` as Namespaced<N, any>, nextState as S, patches);
this.messagingSystem.publish(
`${this.name}:stateChange` as Namespaced<N, any>,
nextState as S,
patches,
);
}

/**
Expand All @@ -187,7 +215,9 @@ export class BaseController<
* listeners from being garbage collected.
*/
protected destroy() {
this.messagingSystem.clearEventSubscriptions(`${this.name}:stateChange` as Namespaced<N, any>);
this.messagingSystem.clearEventSubscriptions(
`${this.name}:stateChange` as Namespaced<N, any>,
);
}
}

Expand Down
Loading

0 comments on commit 0db3170

Please sign in to comment.