/* @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>, // 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; /** * 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>) { /* 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();