all files / modules/ transition.js

100% Statements 68/68
93.1% Branches 54/58
100% Functions 21/21
100% Lines 32/32
8 statements, 2 functions, 10 branches Ignored     
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            66× 66× 66× 66× 66× 66× 44× 44× 44×     66×       66×   66× 42×       42×     42× 42×         66× 62×       62×     62× 62×         66× 66× 10×   10×     10× 10×         66×       66×   66×    
import transitionPath, { nameToIDs } from 'router5.transition-path';
import asyncProcess from './async';
import constants from './constants';
 
export default transition;
 
function transition(router, toState, fromState, callback) {
    let cancelled = false;
    const additionalArgs = router.getAdditionalArgs();
    const isCancelled = () => cancelled;
    const cancel = () => cancelled = true;
    const done = (err, state) => {
        if (!err && !isCancelled() && router.options.autoCleanUp) {
            const activeSegments = nameToIDs(toState.name);
            Object.keys(router._canDeact).forEach(name => {
                if (activeSegments.indexOf(name) === -1) router._canDeact[name] = undefined;
            });
        }
        callback(isCancelled() ? { code: constants.TRANSITION_CANCELLED } : err, state || toState);
    };
 
    const {toDeactivate, toActivate} = transitionPath(toState, fromState);
    const asyncBase = { isCancelled, toState, fromState, additionalArgs: [] };
 
    const canDeactivate = (toState, fromState, cb) => {
        let canDeactivateFunctionMap = toDeactivate
            .filter(name => router._canDeact[name])
            .reduce((fnMap, name) => ({ ...fnMap, [name]: router._canDeact[name] }), {});
 
        asyncProcess(
            canDeactivateFunctionMap, { ...asyncBase, additionalArgs },
            err => {
                const errObj = err ? (err instanceof Error ? { error: err } : { segment: err }) : null;
                cb(err ? { code: constants.CANNOT_DEACTIVATE, ...errObj } : null);
            }
        );
    };
 
    const canActivate = (toState, fromState, cb) => {
        const canActivateFunctionMap = toActivate
            .filter(name => router._canAct[name])
            .reduce((fnMap, name) => ({ ...fnMap, [name]: router._canAct[name] }), {});
 
        asyncProcess(
            canActivateFunctionMap, { ...asyncBase, additionalArgs },
            err => {
                const errObj = err ? (err instanceof Error ? { error: err } : { segment: err }) : null;
                cb(err ? { code: constants.CANNOT_ACTIVATE, ...errObj } : null);
            }
        );
    };
 
    const middlewareFn = router.mware;
    const middleware = (toState, fromState, cb) => {
        let mwareFunction = Array.isArray(router.mware) ? router.mware : [router.mware];
 
        asyncProcess(
            mwareFunction, { ...asyncBase, additionalArgs },
            (err, state) => {
                const errObj = err ? (typeof err === 'object' ? err : { error: err }) : null;
                cb(err ? { code: constants.TRANSITION_ERR, ...errObj } : null, state || toState);
            }
        );
    };
 
    let pipeline = (fromState ? [canDeactivate] : [])
        .concat(canActivate)
        .concat(middlewareFn ? middleware : []);
 
    asyncProcess(pipeline, asyncBase, done);
 
    return cancel;
}