Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | 4x 5x 4x 43x 4x 4x 4x 4x 4x 4x 4x 43x 43x 4x 15x 15x 15x 8x 8x 2x 2x 6x 6x 3x 3x 34x | import { StateController } from "../StateController";
import { produce } from "immer";
export { produce }
type NextFunction<TState> = (state:TState) => void;
type TapFunction<TState> = (product:Product<TState>) => void;
/**
* A monad like class that promotes functional style
* state changes with a StateController
*/
export class Product<TState> {
/**
* Creates a new Product object.
*/
static of<TState>(controller: StateController, stateName?:string) {
return new Product<TState>(controller, stateName || "state");
}
/** A lifting function that calls next */
static nextWith = <TState>(product: Product<TState>) => (fn:NextFunction<TState>) => product.continue(product).next(fn);
/** A lifting function that calls tap */
static tapWith = <TState>(product: Product<TState>) => (fn:TapFunction<TState>) => product.continue(product).tap(fn);
/** A chainable call to requestUpdate */
static requestUpdate = (event:Event|string) => <TState>(product: Product<TState>) => product.requestUpdate(event);
/** A chainable call to dispatchHostEvent */
static dispatchHostEvent = (event:Event) => <TState>(product:Product<TState>) => product.dispatchHostEvent(event);
/** A chainable call to next */
static next = <TState>(fn:NextFunction<TState>) => (product: Product<TState>) => product.next(fn);
/** A chainable call to tap */
static tap = <TState>(fn:TapFunction<TState>) => (product: Product<TState>) => product.tap(fn);
/** Returns the current state */
static getState = <TState>(product: Product<TState>) => product.getState();
/**
*
* @param controller
* @param stateName
*/
constructor(controller: StateController, stateName:string) {
this.controller = controller;
this.stateName = stateName;
}
public controller:StateController;
private stateName:string;
/**
* Returns a snapshot of the state property.
* Similar to a flatten method.
* @returns {TState}
*/
getState():TState {
return this.controller[this.stateName] as TState;
}
/**
* The primary mapping function.
* @param {NextFunction<TState>} fn
* @returns {Product<TState>}
*/
next(fn: NextFunction<TState>) {
const state = this.controller[this.stateName] as TState;
this.controller[this.stateName] = produce(state, (draft:TState) => fn(draft)) as TState;
return this.continue(this);
}
/**
* Use to perform branching operations.
* @param {TapFunction<TState>} fn
* @returns {Product<TState>}
*/
tap(fn: TapFunction<TState>) {
fn(this);
return this.continue(this);
}
/**
* Enables running multiple 'next' functions in a pipe.
* @param {Array<NextFunction<TState>>} fns a series of functions to call next on.
* @returns {Product<TState>}
*/
pipeNext(...fns: Array<NextFunction<TState>>):Product<TState> {
return fns.reduce((v:Product<TState>, f:NextFunction<TState>) => v.next(f), this);
}
/**
* Enables running multiple 'tap' functions in a pipe.
* @param {...any} fns a series of functions to call tap on.
* @returns {Product<TState>}
*/
pipeTap(...fns: Array<TapFunction<TState>>):Product<TState> {
return fns.reduce((v:Product<TState>, f:TapFunction<TState>) => v.tap(f), this);
}
/**
* Calls requestUpdate on the controller.
* @param {Event|string} event
* @returns {Product<TState>}
*/
requestUpdate(event:Event|string) {
this.controller.requestUpdate(event);
return this.continue(this);
}
/**
* Dispatches an event on the controllers host element.
* @param event
* @returns {Product<TState>}
*/
dispatchHostEvent(event:Event) {
this.controller.host.dispatchEvent(event);
return this.continue(this);
}
/**
* Returns a new Product object based on the current one.
* Convenient for mapping methods.
* @returns {Product<TState>}
*/
continue(product:Product<TState>) {
return Product.of<TState>(product.controller, product.stateName);
}
} |