All files Route.js

100% Statements 62/62
100% Branches 18/18
100% Functions 7/7
100% Lines 62/62
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                      45x       206x 206x 206x   206x 1x           205x 1x           204x 1x             203x 203x 200x 200x 200x 200x 1189x 1189x   193x 193x 579x     193x 193x 193x 193x 193x       608x 608x 608x 608x 608x         608x   608x 3238x 3238x 3236x 216x   3020x 3020x     390x 390x         390x       290x 290x 290x 290x           290x 1712x 1712x       276x 276x   2x     274x 18x 18x 6x       268x       593x 593x       291x 291x       2x      
import {
    joinUri,
    forEachPartName,
    chooseTemplate
} from './utils.js';
import RouteOptions from './RouteOptions.js';
import RouteParams from './RouteParams.js';
import TemplateUri from './TemplateUri.js';
import UserUri from './UserUri.js';
import RouterError from './RouterError.js';
 
const metaDataProperties = ['payload', 'key', 'data'];
 
export default class Route {
    constructor (routeName, rawRoute) {
        const rawRouteParams = rawRoute.params || {};
        const rawRouteOptions = rawRoute.options || {};
        const rawRouteUri = rawRoute.uri || '';
 
        if (typeof rawRouteParams !== 'object') {
            throw new RouterError(RouterError.INVALID_INPUT_TYPE, {
                entity: 'route\'s params',
                type: 'object',
                routeName
            });
        }
        if (typeof rawRouteOptions !== 'object') {
            throw new RouterError(RouterError.INVALID_INPUT_TYPE, {
                entity: 'route\'s options',
                type: 'object',
                routeName
            });
        }
        if (typeof rawRouteUri !== 'string') {
            throw new RouterError(RouterError.INVALID_INPUT_TYPE, {
                entity: 'route\'s URI template',
                type: 'string',
                routeName
            });
        }
 
        this.name = routeName;
        const templateUri = new TemplateUri(rawRouteUri);
        const parsedOptions = new RouteOptions(rawRouteOptions, routeName);
        const parsedParams = new RouteParams(rawRouteParams);
        const parsedTemplate = {};
        forEachPartName((partName) => {
            const Template = chooseTemplate(templateUri, partName);
            parsedTemplate[partName] = new Template(templateUri, parsedParams, routeName);
        });
        const parsedMetaData = {};
        for (let metaDataProperty of metaDataProperties) {
            parsedMetaData[metaDataProperty] = rawRoute[metaDataProperty];
        }
 
        this._templateUri = templateUri;
        this._parsedOptions = parsedOptions;
        this._parsedParams = parsedParams;
        this._parsedTemplate = parsedTemplate;
        this._parsedMetaData = parsedMetaData;
    }
 
    matchUri (userUri, contextOptions) {
        const routeName = this.name;
        const parsedTemplate = this._parsedTemplate;
        const matchObject = {};
        const params = {};
        const options = Object.assign(
            {},
            contextOptions.router.getParsedOptions(),
            this._parsedOptions
        );
        Object.assign(contextOptions, options);
 
        for (let p in parsedTemplate) {
            contextOptions.partName = p;
            const matchFragment = parsedTemplate[p].matchParsedValue(userUri, contextOptions);
            if (!matchFragment) {
                return null;
            }
            matchObject[p] = matchFragment.value;
            Object.assign(params, matchFragment.params);
        }
 
        delete options.routeName;
        Object.assign(matchObject, this._parsedMetaData, {
            name: routeName,
            params,
            options
        });
        return matchObject;
    }
 
    generateUri (userParams, contextOptions) {
        const routeName = this.name;
        const parsedTemplate = this._parsedTemplate;
        const generatingUri = {};
        Object.assign(
            contextOptions,
            contextOptions.router.getParsedOptions(),
            this._parsedOptions,
            {generatingUri, routeName}
        );
        for (let p in parsedTemplate) {
            contextOptions.partName = p;
            generatingUri[p] = parsedTemplate[p].generateParsedValue(userParams, contextOptions);
        }
 
        let rawUri;
        try {
            rawUri = joinUri(generatingUri, contextOptions);
        } catch (error) {
            throw new RouterError(RouterError[error.code], {routeName});
        }
 
        if (contextOptions.dataConsistency) {
            const userUri = new UserUri(contextOptions.router.resolveUri(rawUri), contextOptions);
            if (!this.matchUri(userUri, {router: contextOptions.router})) {
                throw new RouterError(RouterError.INCONSISTENT_DATA, {routeName});
            }
        }
 
        return rawUri;
    }
 
    canBeMatched () {
        const parsedOptions = this._parsedOptions;
        return parsedOptions.canBeMatched;
    }
 
    canBeGenerated () {
        const parsedOptions = this._parsedOptions;
        return parsedOptions.canBeGenerated;
    }
 
    getParsedOptions () {
        return this._parsedOptions;
    }
}