(1.1.0) API changes and added some tests
This commit is contained in:
parent
70e426fc20
commit
7013a3c050
@ -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)
|
||||
|
||||
|
||||
@ -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('/');
|
||||
```
|
||||
|
||||
@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
3
packages/router/spec/helpers/globals.js
Normal file
3
packages/router/spec/helpers/globals.js
Normal file
@ -0,0 +1,3 @@
|
||||
self = window = {
|
||||
location: {}
|
||||
};
|
||||
91
packages/router/spec/router.spec.js
Normal file
91
packages/router/spec/router.spec.js
Normal 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();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
7
packages/router/spec/support/jasmine.json
Normal file
7
packages/router/spec/support/jasmine.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"spec_dir": "spec",
|
||||
"spec_files": ["**/*[sS]pec.js"],
|
||||
"helpers": ["helpers/**/*.js"],
|
||||
"stopSpecOnExpectationFailure": false,
|
||||
"random": false
|
||||
}
|
||||
@ -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 VARMATCH_RE = /:([^\/]+)/g;
|
||||
const ROUTEELEMENT_RE = /^[^\/]+$/;
|
||||
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
|
||||
};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user