All files index.js

100% Statements 49/49
75% Branches 3/4
100% Functions 20/20
100% Lines 49/49
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 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174                                                                        1x   1x   1x     6x       10x             5x     5x 5x 1x   5x 5x         12x 1x       1x           1x   1x     2x   10x             2x     2x 2x 2x 2x 3x 7x             7x         7x       7x 7x 7x       2x             1x 1x 1x 1x 1x             8x 7x 7x     8x       2x 5x         2x       5x       2x 2x       12x 30x 30x      
// @flow
 
import {BehaviorSubject} from './observable'
import {factory} from "./subscribe"
import type {Subscribe} from "./subscribe"
import {shallowDiffers} from './shallow-differs'
 
export type Actions = {
    [name: string]: Function
}
 
export type Action = {
    type: string,
    payload: any
}
 
export type State = {
    [name: string]: any,
    actions: Actions
}
 
export type States = {
    [name: string]: State
}
 
export type Store = {
    getState: (name: string) => State | States,
    subscribe: Subscribe,
    dispatch: Function
}
 
export type Reducer = {
    state: any,
    actions: Actions
}
 
const states = {};
 
const subscriptions = [];
 
const state = {};
 
function getState() {
    return state
}
 
function getStateByName(name: string) {
    return {
        [name]: states[name].getValue(),
        ...actions[name]
    }
}
 
function dispatch(action: Action): Promise<Action> {
    const nextStatePromise = Promise.resolve({
        ...state
    });
    return applyMiddlewares(nextStatePromise, action).then(nextState => {
        if(shallowDiffers(state, nextState)) {
            applyNextState(nextState)
        }
        callSubscriptions(action);
        return action
    })
}
 
function callSubscriptions(action: Action) {
    subscriptions.forEach(subscription => {
        subscription.cb(getState(), action)
    });
}
 
export const store: Store = {
    getState,
    subscribe: factory(subscriptions),
    dispatch
};
 
const actions = {};
 
const middlewares = [];
 
function defineGetter(name: string) {
    Object.defineProperty(store, name, {
        get() {
            return getStateByName(name)
        },
        configurable: true
    });
}
 
export function register(name: string, reducer: Reducer) {
    states[name] = new BehaviorSubject({
        ...reducer.state
    });
    state[name] = reducer.state;
    actions[name] = {};
    defineGetter(name);
    for (const actionName in reducer.actions) {
        actions[name][actionName] = function () {
            const nextStatePromise = Promise.resolve(
                reducer.actions[actionName].call(
                    null,
                    states[name].getValue(),
                    ...Array.from(arguments)
                )
            ).then(value => {
                return {
                    ...state,
                    [name]: value
                }
            });
            const action: Action = {
                type: actionName,
                payload: Array.from(arguments)
            };
            return applyMiddlewares(nextStatePromise, action).then(nextState => {
                applyNextState(nextState);
                callSubscriptions(action)
            })
        }
    }
    return dispatch({
        type: 'REGISTER_REDUCER',
        payload: name
    });
}
 
export function remove(name: string) {
    delete states[name];
    delete state[name];
    delete actions[name];
    delete store[name];
    return dispatch({
        type: 'REMOVE_REDUCER',
        payload: name
    })
}
 
function applyNextState(nextState: State) {
    for (const i in states) {
        Eif (shallowDiffers(nextState[i], states[i].getValue())) {
            states[i].next(nextState[i])
        }
    }
    Object.assign(state, nextState);
}
 
export function subscribe(name: string, fn: Function) {
    const subscription = states[name].subscribe(nextState => {
        fn({
            [name]: nextState,
            ...actions[name]
        })
    });
    return subscription
}
 
export function use(middleware: Function) {
    middlewares.push(middleware)
}
 
export function unuse(middleware: Function) {
    const index = middlewares.indexOf(middleware);
    middlewares.splice(index, 1)
}
 
function applyMiddlewares(statePromise: Promise<any>, action: Action): Promise<any> {
    return middlewares.reduce((promise, middleware, i) => {
        return promise.then(value => {
            return middleware(store, Promise.resolve(value), action)
        })
    }, Promise.resolve(statePromise))
}