120 lines
3.1 KiB
JavaScript
120 lines
3.1 KiB
JavaScript
/* @flow */
|
|
|
|
import { Component } from 'react';
|
|
|
|
/**
|
|
* Object describing application route.
|
|
*
|
|
* @typedef {Object} Route
|
|
* @property {Component} component - React Component constructor.
|
|
* @property {string} path - URL route, required for web routing.
|
|
*/
|
|
type Route = {
|
|
component: Class<Component<*>>, // eslint-disable-line no-undef
|
|
path: string
|
|
};
|
|
|
|
/**
|
|
* A registry for Navigator routes, allowing features to register themselves
|
|
* without needing to create additional inter-feature dependencies.
|
|
*/
|
|
class RouteRegistry {
|
|
_elements: Array<Route>;
|
|
|
|
/**
|
|
* Initializes a new RouteRegistry instance.
|
|
*/
|
|
constructor() {
|
|
/**
|
|
* The set of registered routes.
|
|
*
|
|
* @private
|
|
* @type {Route[]}
|
|
*/
|
|
this._elements = [];
|
|
}
|
|
|
|
/**
|
|
* Determines whether two specific Routes are equal i.e. they describe one
|
|
* and the same abstract route.
|
|
*
|
|
* @param {Object} a - The Route to compare to b.
|
|
* @param {Object} b - The Route to compare to a.
|
|
* @returns {boolean} True if the specified a and b describe one and the
|
|
* same abstract route; otherwise, false.
|
|
*/
|
|
areRoutesEqual(a: Route, b: Route) {
|
|
if (a === b) { // reflexive
|
|
return true;
|
|
}
|
|
if (!a) {
|
|
return !b;
|
|
}
|
|
if (!b) {
|
|
return !a;
|
|
}
|
|
|
|
const aKeys = Object.keys(a);
|
|
const bKeys = Object.keys(b);
|
|
|
|
return (
|
|
aKeys.length === bKeys.length /* symmetric */
|
|
&& aKeys.every(key => a[key] === b[key]));
|
|
}
|
|
|
|
/**
|
|
* Returns all registered routes.
|
|
*
|
|
* @returns {Route[]}
|
|
*/
|
|
getRoutes() {
|
|
// We use the destructuring operator to 'clone' the route object to
|
|
// prevent modifications from outside (e.g. React Native's Navigator
|
|
// extends it with additional properties).
|
|
return this._elements.map(r => {
|
|
return { ...r };
|
|
});
|
|
}
|
|
|
|
/* eslint-disable no-undef */
|
|
|
|
/**
|
|
* Returns registered route by name if any.
|
|
*
|
|
* @param {Component} component - The React Component (class) of the route
|
|
* to retrieve.
|
|
* @returns {Route|null}
|
|
*/
|
|
getRouteByComponent(component: Class<Component<*>>) {
|
|
|
|
/* eslint-enable no-undef */
|
|
|
|
const route = this._elements.find(r => r.component === component);
|
|
|
|
// We use destructuring operator to 'clone' route object to prevent
|
|
// modifications from outside (e.g. React Native's Navigator extends
|
|
// it with some additional properties).
|
|
return route ? { ...route } : null;
|
|
}
|
|
|
|
/**
|
|
* Adds a route to this registry.
|
|
*
|
|
* @param {Route} route - Route definition object.
|
|
* @returns {void}
|
|
*/
|
|
register(route: Route) {
|
|
if (this._elements.includes(route)) {
|
|
throw new Error(
|
|
`Route ${String(route.component)} is registered already!`);
|
|
}
|
|
|
|
this._elements.push(route);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The public singleton instance of the RouteRegistry class.
|
|
*/
|
|
export default new RouteRegistry();
|