(1.1.0) API changes and added some tests

This commit is contained in:
Timothy Farrell 2017-01-23 16:27:47 -06:00
parent 70e426fc20
commit 7013a3c050
7 changed files with 139 additions and 23 deletions

View File

@ -15,7 +15,7 @@ A utility to expose an asynchronous API between a web worker and its parent.
## [Router](./packages/router/README.md)
A slim and unopinionated router.
A slim and unopinionated hash router.
## [Trimkit](./packages/trimkit/README.md)

View File

@ -11,8 +11,8 @@ navigated. Parameters are: api (Router instance) badpath (string) lastGoodRoute
descriptor object for the last good route.
returns an api object: goto(path) - match the path to a route and navigate there href(pathName,
vars) - build a path based on the name and supplied vars listen() - listen to window.onhashchange
for route changes current() - get the current route descriptor object
vars) - build a path based on the name and supplied vars start(initialRoute) - listen to
window.onhashchange for route changes current() - get the current route descriptor object
Example:
@ -45,4 +45,5 @@ const router = Router(
r.goto(lastGoodRoute.path || 'home');
}
);
router.start('/');
```

View File

@ -1,6 +1,6 @@
{
"name": "router",
"version": "1.0.0",
"version": "1.1.0",
"description": "A slim and unopinionated router",
"main": "lib/index.js",
"jsnext:main": "src/index.js",
@ -14,7 +14,8 @@
"npm run build:umd && uglifyjs -m --screw-ie8 -c -o dist/router.min.js dist/router.js",
"build:umd:gzip": "npm run build:umd:min && gzip -c9 dist/router.min.js > dist/router.min.js.gz",
"build": "npm run build:umd:gzip && ls -l dist/",
"prepublish": "npm run clean && npm run build"
"prepublish": "npm run clean && npm run build",
"test": "npm run build:lib && jasmine --verbose"
},
"repository": {
"type": "git",
@ -41,6 +42,7 @@
"uglifyjs": "2.4.10"
},
"dependencies": {
"jasmine": "^2.5.3",
"trimkit": "^1.0.2"
}
}

View File

@ -0,0 +1,3 @@
self = window = {
location: {}
};

View File

@ -0,0 +1,91 @@
const { Router } = require('../lib/index.js');
describe('router builds urls', () => {
describe('for hashed routes', () => {
const router = Router(
'#',
{
home: {
path: '/',
onenter: (r, route) => {},
onexit: (r, route, newRoute) => {}
},
article: {
path: '/article/:id',
vars: { id: /[a-f0-9]{6,40}/ },
onenter: (r, route) => {},
onexit: (r, route, newRoute) => {}
}
},
(r, path, lastGoodRoute) => {}
);
it('at the root', () => {
expect(router.href('home')).toEqual('#/');
});
it('with variables', () => {
expect(router.href('article', { id: 156234 })).toEqual('#/article/156234');
});
describe('but throws an error', () => {
it("if the route doesn't exist", () => {
expect(() => {
router.href('artcle', { id: 156 });
}).toThrowError(Error, 'Invalid route artcle.');
});
it("if the vars don't match", () => {
expect(() => {
router.href('article', { id: 156 });
}).toThrowError(Error, 'Invalid value for route /article/:id var id: 156.');
});
});
});
});
describe('router goes to routes', () => {
describe('for hashed routes', () => {
const router = Router(
'#',
{
home: {
path: '/',
onenter: (r, route) => {},
onexit: (r, route, newRoute) => {}
},
article: {
path: '/article/:id',
vars: { id: /[a-f0-9]{6,40}/ },
onenter: (r, route) => {},
onexit: (r, route, newRoute) => {}
}
},
(r, path, lastGoodRoute) => {}
);
it('at the root', done => {
router.goto('home').then(() => {
const current = router.current();
expect(current.name).toEqual('home');
expect(current.path).toEqual('#/');
done();
});
});
it('with vars', done => {
router.goto('article', { id: 156234 }).then(() => {
const current = router.current();
expect(current.name).toEqual('article');
expect(current.path).toEqual('#/article/156234');
done();
});
});
it('with a url', done => {
router.goto('#/article/156233').then(() => {
const current = router.current();
expect(current.name).toEqual('article');
expect(current.path).toEqual('#/article/156233');
done();
});
});
});
});

View File

@ -0,0 +1,7 @@
{
"spec_dir": "spec",
"spec_files": ["**/*[sS]pec.js"],
"helpers": ["helpers/**/*.js"],
"stopSpecOnExpectationFailure": false,
"random": false
}

View File

@ -1,16 +1,10 @@
import { isFunction, isUndefined, Null, ObjectKeys } from 'trimkit';
function nop() {}
export function Router(baseUrl, routes, unmatched) {
let listening = false;
let currentRoute = Null;
let reEnterHook = Null;
const VARMATCH_RE = /:([^\/]+)/g;
const ROUTEELEMENT_RE = /^[^\/]+$/;
const routeMatcher = ObjectKeys(routes).map(name => {
const nop = () => 1;
const digestRoutes = (routes, baseUrl) =>
ObjectKeys(routes).map(name => {
const route = routes[name];
const reg = route.path.replace(VARMATCH_RE, (m, varName) => {
const varDef = route.vars || {};
@ -25,6 +19,13 @@ export function Router(baseUrl, routes, unmatched) {
};
});
export function Router(baseUrl, routes, unmatched) {
let listening = false;
let currentRoute = Null;
let reEnterHook = Null;
let routeMatcher = digestRoutes(routes, baseUrl);
function goto(urlOrName, vars) {
const url = urlOrName.startsWith(baseUrl) ? urlOrName : href(urlOrName, vars);
@ -69,7 +70,9 @@ export function Router(baseUrl, routes, unmatched) {
currentRoute = newRoute;
} else {
let onexit = currentRoute && currentRoute.name ? routes[currentRoute.name].onexit || nop : nop;
Promise.resolve(onexit(api, currentRoute, newRoute)).then(() => {
return Promise.resolve(onexit(api, currentRoute, newRoute))
.catch(() => {})
.then(() => {
reEnterHook = routes[routeMatch.name].onenter(api, newRoute);
currentRoute = newRoute;
});
@ -111,16 +114,24 @@ export function Router(baseUrl, routes, unmatched) {
return location.hash;
}
function listen(initialRoute) {
function _handler() {
goto(_location());
}
function start(initialRoute) {
if (listening) {
return;
}
self.addEventListener('hashchange', () => goto(_location()), false);
self.addEventListener('hashchange', _handler, false);
listening = true;
goto(_location() || initialRoute);
}
function stop() {
self.removeEventListener('hashchange', _handler);
}
function current() {
return currentRoute;
}
@ -128,7 +139,8 @@ export function Router(baseUrl, routes, unmatched) {
const api = {
goto,
href,
listen,
start,
stop,
current
};