UNPKG

universal-router

Version:

Isomorphic router for JavaScript web applications

243 lines (198 loc) 7.35 kB
/*! Universal Router | MIT License | https://www.kriasoft.com/universal-router/ */ import pathToRegexp from 'path-to-regexp'; /** * Universal Router (https://www.kriasoft.com/universal-router/) * * Copyright © 2015-present Kriasoft, LLC. All rights reserved. * * This source code is licensed under the Apache 2.0 license found in the * LICENSE.txt file in the root directory of this source tree. */ var hasOwnProperty = Object.prototype.hasOwnProperty; var cache = new Map(); function decodeParam(val) { try { return decodeURIComponent(val); } catch (err) { return val; } } function matchPath(route, pathname, parentKeys, parentParams) { var end = !route.children; var cacheKey = (route.path || '') + '|' + end; var regexp = cache.get(cacheKey); if (!regexp) { var keys = []; regexp = { keys: keys, pattern: pathToRegexp(route.path || '', keys, { end: end }) }; cache.set(cacheKey, regexp); } var m = regexp.pattern.exec(pathname); if (!m) { return null; } var path = m[0]; var params = Object.assign({}, parentParams); for (var i = 1; i < m.length; i += 1) { var key = regexp.keys[i - 1]; var prop = key.name; var value = m[i]; if (value !== undefined || !hasOwnProperty.call(params, prop)) { if (key.repeat) { params[prop] = value ? value.split(key.delimiter).map(decodeParam) : []; } else { params[prop] = value ? decodeParam(value) : value; } } } return { path: !end && path.charAt(path.length - 1) === '/' ? path.substr(1) : path, keys: parentKeys.concat(regexp.keys), params: params }; } /** * Universal Router (https://www.kriasoft.com/universal-router/) * * Copyright © 2015-present Kriasoft, LLC. All rights reserved. * * This source code is licensed under the Apache 2.0 license found in the * LICENSE.txt file in the root directory of this source tree. */ function matchRoute(route, baseUrl, pathname, parentKeys, parentParams) { var match = void 0; var childMatches = void 0; var childIndex = 0; return { next: function next(routeToSkip) { if (route === routeToSkip) { return { done: true }; } if (!match) { match = matchPath(route, pathname, parentKeys, parentParams); if (match) { return { done: false, value: { route: route, baseUrl: baseUrl, path: match.path, keys: match.keys, params: match.params } }; } } if (match && route.children) { while (childIndex < route.children.length) { if (!childMatches) { var childRoute = route.children[childIndex]; childRoute.parent = route; childMatches = matchRoute(childRoute, baseUrl + match.path, pathname.substr(match.path.length), match.keys, match.params); } var childMatch = childMatches.next(routeToSkip); if (!childMatch.done) { return { done: false, value: childMatch.value }; } childMatches = null; childIndex += 1; } } return { done: true }; } }; } /** * Universal Router (https://www.kriasoft.com/universal-router/) * * Copyright © 2015-present Kriasoft, LLC. All rights reserved. * * This source code is licensed under the Apache 2.0 license found in the * LICENSE.txt file in the root directory of this source tree. */ function resolveRoute(context, params) { if (typeof context.route.action === 'function') { return context.route.action(context, params); } return undefined; } var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /** * Universal Router (https://www.kriasoft.com/universal-router/) * * Copyright © 2015-present Kriasoft, LLC. All rights reserved. * * This source code is licensed under the Apache 2.0 license found in the * LICENSE.txt file in the root directory of this source tree. */ function isChildRoute(parentRoute, childRoute) { var route = childRoute; while (route) { route = route.parent; if (route === parentRoute) { return true; } } return false; } var UniversalRouter = function () { function UniversalRouter(routes) { var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; _classCallCheck(this, UniversalRouter); if (Object(routes) !== routes) { throw new TypeError('Invalid routes'); } this.baseUrl = options.baseUrl || ''; this.resolveRoute = options.resolveRoute || resolveRoute; this.context = Object.assign({ router: this }, options.context); this.root = Array.isArray(routes) ? { path: '', children: routes, parent: null } : routes; this.root.parent = null; } _createClass(UniversalRouter, [{ key: 'resolve', value: function resolve(pathnameOrContext) { var context = Object.assign({}, this.context, typeof pathnameOrContext === 'string' ? { pathname: pathnameOrContext } : pathnameOrContext); var match = matchRoute(this.root, this.baseUrl, context.pathname.substr(this.baseUrl.length), [], null); var resolve = this.resolveRoute; var matches = null; var nextMatches = null; function next(resume) { var parent = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : matches.value.route; var prevResult = arguments[2]; var routeToSkip = prevResult === null && matches.value.route; matches = nextMatches || match.next(routeToSkip); nextMatches = null; if (!resume) { if (matches.done || !isChildRoute(parent, matches.value.route)) { nextMatches = matches; return Promise.resolve(null); } } if (matches.done) { return Promise.reject(Object.assign(new Error('Page not found'), { context: context, status: 404, statusCode: 404 })); } return Promise.resolve(resolve(Object.assign({}, context, matches.value), matches.value.params)).then(function (result) { if (result !== null && result !== undefined) { return result; } return next(resume, parent, result); }); } context.next = next; return next(true, this.root); } }]); return UniversalRouter; }(); UniversalRouter.pathToRegexp = pathToRegexp; UniversalRouter.matchPath = matchPath; UniversalRouter.matchRoute = matchRoute; UniversalRouter.resolveRoute = resolveRoute; export default UniversalRouter; //# sourceMappingURL=browser.mjs.map