From d56a00a316e4c5592b7d422536b384653e60d8de Mon Sep 17 00:00:00 2001 From: Kimmo Puputti Date: Wed, 15 Feb 2017 15:31:39 +0200 Subject: [PATCH] Move route util functions to a separate module --- src/app.js | 3 +- src/components/NamedLink/NamedLink.js | 2 +- src/components/NamedRedirect/NamedRedirect.js | 2 +- src/index.js | 2 +- src/routesConfiguration.js | 75 ------------------ src/util/routes.js | 76 +++++++++++++++++++ 6 files changed, 81 insertions(+), 79 deletions(-) create mode 100644 src/util/routes.js diff --git a/src/app.js b/src/app.js index b032c8fb..c13f99cb 100644 --- a/src/app.js +++ b/src/app.js @@ -8,7 +8,8 @@ import en from 'react-intl/locale-data/en'; import configureStore from './store'; import Routes from './Routes'; import { RoutesProvider } from './components'; -import routesConfiguration, { flattenRoutes } from './routesConfiguration'; +import routesConfiguration from './routesConfiguration'; +import { flattenRoutes } from './util/routes'; import localeData from './translations/en.json'; export const ClientApp = props => { diff --git a/src/components/NamedLink/NamedLink.js b/src/components/NamedLink/NamedLink.js index ec81bf1d..4a285bbc 100644 --- a/src/components/NamedLink/NamedLink.js +++ b/src/components/NamedLink/NamedLink.js @@ -5,7 +5,7 @@ */ import React, { PropTypes } from 'react'; import { Link } from 'react-router-dom'; -import { pathByRouteName } from '../../routesConfiguration'; +import { pathByRouteName } from '../../util/routes'; const NamedLink = (props, context) => { const { name, search, hash, state, params, ...rest } = props; diff --git a/src/components/NamedRedirect/NamedRedirect.js b/src/components/NamedRedirect/NamedRedirect.js index 8e5256ce..fa75dae5 100644 --- a/src/components/NamedRedirect/NamedRedirect.js +++ b/src/components/NamedRedirect/NamedRedirect.js @@ -5,7 +5,7 @@ */ import React, { PropTypes } from 'react'; import { Redirect } from 'react-router-dom'; -import { pathByRouteName } from '../../routesConfiguration'; +import { pathByRouteName } from '../../util/routes'; const NamedRedirect = (props, context) => { const { name, search, state, params, ...rest } = props; diff --git a/src/index.js b/src/index.js index 8f61618f..62052893 100644 --- a/src/index.js +++ b/src/index.js @@ -15,7 +15,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { ClientApp, renderApp } from './app'; import configureStore from './store'; -import { matchPathname } from './routesConfiguration'; +import { matchPathname } from './util/routes'; import rootSaga from './sagas'; import './index.css'; diff --git a/src/routesConfiguration.js b/src/routesConfiguration.js index f1d559e9..f38109e3 100644 --- a/src/routesConfiguration.js +++ b/src/routesConfiguration.js @@ -1,7 +1,4 @@ import React from 'react'; -import { find } from 'lodash'; -import { matchPath } from 'react-router-dom'; -import pathToRegexp from 'path-to-regexp'; import { NamedRedirect } from './components'; import { AuthenticationPage, @@ -261,76 +258,4 @@ const routesConfiguration = [ }, ]; -const flattenRoutes = routesArray => - routesArray.reduce((a, b) => a.concat(b.routes ? [b].concat(flattenRoutes(b.routes)) : b), []); - -const findRouteByName = (nameToFind, routes) => { - const flattenedRoutes = flattenRoutes(routes); - return find(flattenedRoutes, route => route.name === nameToFind); -}; - -/** - * E.g. ```const toListingPath = toPathByRouteName('ListingPage', routes);``` - * Then we can generate listing paths with given params (```toListingPath({ id: uuidX })```) - */ -const toPathByRouteName = (nameToFind, routes) => { - const route = findRouteByName(nameToFind, routes); - if (!route) { - throw new Error(`Path "${nameToFind}" was not found.`); - } - return pathToRegexp.compile(route.path); -}; - -/** - * Shorthand for single path call. (```pathByRouteName('ListingPage', routes, { id: uuidX });```) - */ -const pathByRouteName = (nameToFind, routes, params = {}) => - toPathByRouteName(nameToFind, routes)(params); - -/** - * matchRoutesToLocation helps to figure out which routes are related to given location. - */ -const matchRoutesToLocation = (routes, location, matchedRoutes = [], params = {}) => { - let parameters = { ...params }; - let matched = [...matchedRoutes]; - - routes.forEach(route => { - const { exact = false } = route; - const match = !route.path || matchPath(location.pathname, route.path, { exact }); - - if (match) { - matched.push(route); - - if (match.params) { - parameters = { ...parameters, ...match.params }; - } - } - - if (route.routes) { - const { matchedRoutes: subRouteMatches, params: subRouteParams } = matchRoutesToLocation( - route.routes, - location, - matched, - parameters, - ); - matched = matched.concat(subRouteMatches); - parameters = { ...parameters, ...subRouteParams }; - } - }); - - return { matchedRoutes: matched, params: parameters }; -}; - -const matchPathnameCreator = routes => - (location, matchedRoutes = [], params = {}) => - matchRoutesToLocation(routes, { pathname: location }, matchedRoutes, params); - -/** - * matchRoutesToLocation helps to figure out which routes are related to given location. - */ -const matchPathname = matchPathnameCreator(routesConfiguration); - -// Exported helpers -export { findRouteByName, flattenRoutes, matchPathname, toPathByRouteName, pathByRouteName }; - export default routesConfiguration; diff --git a/src/util/routes.js b/src/util/routes.js new file mode 100644 index 00000000..b7e338a7 --- /dev/null +++ b/src/util/routes.js @@ -0,0 +1,76 @@ +import { find } from 'lodash'; +import { matchPath } from 'react-router-dom'; +import pathToRegexp from 'path-to-regexp'; +import routesConfiguration from '../routesConfiguration'; + +const flattenRoutes = routesArray => + routesArray.reduce((a, b) => a.concat(b.routes ? [b].concat(flattenRoutes(b.routes)) : b), []); + +const findRouteByName = (nameToFind, routes) => { + const flattenedRoutes = flattenRoutes(routes); + return find(flattenedRoutes, route => route.name === nameToFind); +}; + +/** + * E.g. ```const toListingPath = toPathByRouteName('ListingPage', routes);``` + * Then we can generate listing paths with given params (```toListingPath({ id: uuidX })```) + */ +const toPathByRouteName = (nameToFind, routes) => { + const route = findRouteByName(nameToFind, routes); + if (!route) { + throw new Error(`Path "${nameToFind}" was not found.`); + } + return pathToRegexp.compile(route.path); +}; + +/** + * Shorthand for single path call. (```pathByRouteName('ListingPage', routes, { id: uuidX });```) + */ +const pathByRouteName = (nameToFind, routes, params = {}) => + toPathByRouteName(nameToFind, routes)(params); + +/** + * matchRoutesToLocation helps to figure out which routes are related to given location. + */ +const matchRoutesToLocation = (routes, location, matchedRoutes = [], params = {}) => { + let parameters = { ...params }; + let matched = [...matchedRoutes]; + + routes.forEach(route => { + const { exact = false } = route; + const match = !route.path || matchPath(location.pathname, route.path, { exact }); + + if (match) { + matched.push(route); + + if (match.params) { + parameters = { ...parameters, ...match.params }; + } + } + + if (route.routes) { + const { matchedRoutes: subRouteMatches, params: subRouteParams } = matchRoutesToLocation( + route.routes, + location, + matched, + parameters, + ); + matched = matched.concat(subRouteMatches); + parameters = { ...parameters, ...subRouteParams }; + } + }); + + return { matchedRoutes: matched, params: parameters }; +}; + +const matchPathnameCreator = routes => + (location, matchedRoutes = [], params = {}) => + matchRoutesToLocation(routes, { pathname: location }, matchedRoutes, params); + +/** + * matchRoutesToLocation helps to figure out which routes are related to given location. + */ +const matchPathname = matchPathnameCreator(routesConfiguration); + +// Exported helpers +export { findRouteByName, flattenRoutes, matchPathname, toPathByRouteName, pathByRouteName };