All files route-task.ts

96.77% Statements 60/62
96.66% Branches 29/30
100% Functions 4/4
96.77% Lines 60/62

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 1032x           2x     2x         2x 2x         2x 753x 753x   2x 11701x 11701x 2x                           835x 835x   835x 5875x 2x 2x   5873x 5873x 5873x 5875x 16x 16x   5875x 23x 23x   5834x 4038x 774x 774x 774x 3190x 10x 10x 6x 6x 6x 6x 6x 6x 3187x     6x 6x 6x 6x 6x 6x 6x 4x 4x   2x 2x 2x 2x 2x 2x 2x 2x 2x              
import {
    RouteNavigationAbortedError,
    RouteSelfRedirectionError,
    RouteTaskCancelledError,
    RouteTaskExecutionError
} from './error';
import { Route } from './route';
import type { Router } from './router';
import type { RouteConfirmHook, RouteConfirmHookResult } from './types';
import { isUrlEqual, isValidConfirmHookResult } from './util';
 
/**
 * Controls the execution and cancellation of a route task.
 */
export class RouteTaskController {
    private _aborted = false;
 
    /**
     * Aborts the current task.
     */
    abort(): void {
        this._aborted = true;
    }
 
    shouldCancel(name: string): boolean {
        return this._aborted;
    }
}
 
export interface RouteTaskOptions {
    to: Route;
    from: Route | null;
    tasks: RouteTask[];
    router: Router;
    /**
     * Optional route task controller.
     * Used to control the execution and cancellation of the task.
     */
    controller?: RouteTaskController;
}
 
export async function createRouteTask(opts: RouteTaskOptions): Promise<Route> {
    const { to, from, tasks, controller, router } = opts;
 
    for (const task of tasks) {
        if (controller?.shouldCancel(task.name)) {
            throw new RouteTaskCancelledError(task.name, to, from);
        }
 
        let result: RouteConfirmHookResult | null = null;
        try {
            result = await task.task(to, from, router);
        } catch (e) {
            throw new RouteTaskExecutionError(task.name, to, from, e);
        }
 
        if (controller?.shouldCancel(task.name)) {
            throw new RouteTaskCancelledError(task.name, to, from);
        }
 
        if (!isValidConfirmHookResult(result)) continue;
        if (typeof result === 'function') {
            to.handle = result;
            return to;
        }
        if (result === false) {
            throw new RouteNavigationAbortedError(task.name, to, from);
        }
        const nextTo = new Route({
            options: router.parsedOptions,
            toType: to.type,
            toInput: result,
            from: to.url
        });
        if (isUrlEqual(nextTo.url, to.url)) {
            throw new RouteSelfRedirectionError(to.fullPath, to, from);
        }
        return createRouteTask({
            ...opts,
            to: nextTo,
            from: to,
            controller
        });
    }
    return to;
}
 
export enum RouteTaskType {
    fallback = 'fallback',
    override = 'override',
    asyncComponent = 'asyncComponent',
    beforeEach = 'beforeEach',
    beforeEnter = 'beforeEnter',
    beforeUpdate = 'beforeUpdate',
    beforeLeave = 'beforeLeave',
    confirm = 'confirm'
}
 
export interface RouteTask {
    name: string;
    task: RouteConfirmHook;
}