universal-router
Version:
Isomorphic router for JavaScript web applications
243 lines (198 loc) • 7.35 kB
JavaScript
/*! 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