diff --git a/.eslintrc b/.eslintrc index 11d01f9..f92be0d 100644 --- a/.eslintrc +++ b/.eslintrc @@ -6,7 +6,7 @@ "no-unexpected-multiline": 2, "no-unreachable": 2, "quotes": [2, "single"], - "semi": [2, "never"] + "semi": "error" }, "env": { "browser": true, diff --git a/README.md b/README.md index d1ecfeb..5f23ccf 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,9 @@ I wanted a library that could be used both on the client and server side without I also wanted a library that gave more flexibility for defining routes. ## Status -**NOTE**: This is currently a Work in progress. -I'm not yet sure if this will be the routing library I want. +**NOTE**: This is an archived project. +There is no roadmap for updates. +There may be updates to dependencies for security updates. ## Design diff --git a/lib/error.js b/lib/error.js index 765cf74..2a1ab48 100644 --- a/lib/error.js +++ b/lib/error.js @@ -1,14 +1,14 @@ -var util = require('util') +var util = require('util'); function NotFound(message, options) { - Error.call(this) - options = options || {} - this.message = message || '' - this.location = options.location || '' + Error.call(this); + options = options || {}; + this.message = message || ''; + this.location = options.location || ''; } -util.inherits(NotFound, Error) +util.inherits(NotFound, Error); module.exports = { NotFound: NotFound -} +}; diff --git a/lib/route-node.js b/lib/route-node.js index ece1538..7d6e5f6 100644 --- a/lib/route-node.js +++ b/lib/route-node.js @@ -1,119 +1,117 @@ -'use strict' -var NotFoundError = require('./error').NotFound -var utils = require('./utils') +var NotFoundError = require('./error').NotFound; +var utils = require('./utils'); -var assign = utils.assign -var isFunction = utils.isFunction -var isRegExp = utils.isRegExp -var isString = utils.isString -var noop = utils.noop +var assign = utils.assign; +var isFunction = utils.isFunction; +var isRegExp = utils.isRegExp; +var isString = utils.isString; +var noop = utils.noop; function RouteNode () { - this._children = Object.create(null) - this._funcs = Object.create(null) - this._regExs = Object.create(null) + this._children = Object.create(null); + this._funcs = Object.create(null); + this._regExs = Object.create(null); } assign(RouteNode.prototype, { handler: null, add: function add(parts, handler, context) { - parts = parts || [] - handler = handler || noop - context = context || null + parts = parts || []; + handler = handler || noop; + context = context || null; if (parts.length === 0) { - this.handler = handler - this.context = context - return this + this.handler = handler; + this.context = context; + return this; } - var part = parts.shift() - var node = null + var part = parts.shift(); + var node = null; if (isString(part)) { - node = this._children[part] + node = this._children[part]; } else if (isRegExp(part)) { - this._regExs[part] = part + this._regExs[part] = part; } else if (isFunction(part)) { - this._funcs[part] = part + this._funcs[part] = part; } if (node == null) { - node = new RouteNode() - this._children[part] = node + node = new RouteNode(); + this._children[part] = node; } - return node.add(parts, handler, context) + return node.add(parts, handler, context); }, get: function get(parts, args, done) { - parts = parts || [] - args = args || [] + parts = parts || []; + args = args || []; if (parts.length === 0) { - return done(null, this.handler, this.context, args) + return done(null, this.handler, this.context, args); } - var part = parts.shift() + var part = parts.shift(); // Check exact matches if (this._children[part]) { - return this._children[part].get(parts, args, done) + return this._children[part].get(parts, args, done); } // Check regex matches - var results = this._getRegexChild(part) + var results = this._getRegexChild(part); if (results && results.node) { - return results.node.get(parts, args.concat(results.args), done) + return results.node.get(parts, args.concat(results.args), done); } // Check function matches - results = this._getFunctionChild(part) + results = this._getFunctionChild(part); if (results && results.node) { - return results.node.get(parts, args.concat(results.args), done) + return results.node.get(parts, args.concat(results.args), done); } - return done(new NotFoundError('not found', {location: parts})) + return done(new NotFoundError('not found', {location: parts})); }, _getRegexChild: function _getRegexChild(part) { - var self = this + var self = this; return Object.keys(this._regExs).reduce(function checkRegex(memo, key) { if (memo) { - return memo + return memo; } - var regex = self._regExs[key] - var results = regex.exec(part) + var regex = self._regExs[key]; + var results = regex.exec(part); if (!results) { - return null + return null; } - var lastIndex = null - var args = [] + var lastIndex = null; + var args = []; while (results && results.index !== lastIndex) { - args = args.concat(results[0]) - lastIndex = results.index - results = regex.exec(part) + args = args.concat(results[0]); + lastIndex = results.index; + results = regex.exec(part); } - return {args: args, key: key, node: self._children[key]} - }, null) + return {args: args, key: key, node: self._children[key]}; + }, null); }, _getFunctionChild: function _getFunctionChild(part) { - var self = this + var self = this; return Object.keys(self._funcs).reduce(function checkFunc(memo, key) { if (memo) { - return memo + return memo; } - var func = self._funcs[key] - var result = func(part) + var func = self._funcs[key]; + var result = func(part); if (result) { - return {args: [result], key: key, node: self._children[key]} + return {args: [result], key: key, node: self._children[key]}; } else { - return null + return null; } - }, null) + }, null); } +}); -}) - -module.exports = RouteNode +module.exports = RouteNode; diff --git a/lib/router.js b/lib/router.js index e32ffb9..57aec91 100644 --- a/lib/router.js +++ b/lib/router.js @@ -1,46 +1,45 @@ -'use strict' -var url = require('url') -var NotFoundError = require('./error').NotFound -var RouteNode = require('./route-node') -var utils = require('./utils') +var url = require('url'); +var NotFoundError = require('./error').NotFound; +var RouteNode = require('./route-node'); +var utils = require('./utils'); -var assign = utils.assign -var isArray = utils.isArray -var isFunction = utils.isFunction -var isString = utils.isString -var noop = utils.noop +var assign = utils.assign; +var isArray = utils.isArray; +var isFunction = utils.isFunction; +var isString = utils.isString; +var noop = utils.noop; function Router() { - this.routes = new RouteNode() + this.routes = new RouteNode(); } assign(Router.prototype, { add: function add(path, handler) { - return this.routes.add(this._uriToParts(path), handler) + return this.routes.add(this._uriToParts(path), handler); }, route: function route(path, options, done) { if (done == null && isFunction(options)) { - done = options - options = {} + done = options; + options = {}; } - options = options || {} - var routeArray = this._uriToParts(path) - done = done || noop + options = options || {}; + var routeArray = this._uriToParts(path); + done = done || noop; function _routeCallback(err, func, context, args) { if (err) { - return done(err) + return done(err); } else { if (isFunction(func)) { - return done(null, func.apply(context, args)) + return done(null, func.apply(context, args)); } else { - return done(new NotFoundError('not found', {location: path})) + return done(new NotFoundError('not found', {location: path})); } } } - return this.routes.get(routeArray, (options.args || []), _routeCallback) + return this.routes.get(routeArray, (options.args || []), _routeCallback); }, _uriToParts: function _uriToParts(uri) { @@ -48,25 +47,25 @@ assign(Router.prototype, { return url.parse(uri) .pathname .split('/') - .filter(function (str) { return str !== ''}) + .filter(function (str) { return str !== ''; }); } else if (isArray(uri)) { - return uri.reduce(this._uriToPartsReducer.bind(this), []) + return uri.reduce(this._uriToPartsReducer.bind(this), []); } }, _uriToPartsReducer: function _uriToPartsReducer(memo, item) { if (isArray(item)) { - return memo.concat(item) + return memo.concat(item); } else if (isString(item)) { - return memo.concat(this._uriToParts(item)) + return memo.concat(this._uriToParts(item)); } else { - return memo.concat(item) + return memo.concat(item); } } -}) +}); Router.isNotFound = function isNotFound(err) { - return err instanceof NotFoundError -} + return err instanceof NotFoundError; +}; -module.exports = Router +module.exports = Router; diff --git a/lib/utils.js b/lib/utils.js index ea919aa..61d4758 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -1,39 +1,37 @@ -'use strict' - -var toString = ({}).toString -var hasOwnProp = ({}).hasOwnProperty +var toString = ({}).toString; +var hasOwnProp = ({}).hasOwnProperty; var utils = { noop: function noop() {}, isString: function isString(str) { - return typeof str === 'string' + return typeof str === 'string'; }, forEach: function forEach(obj, fn) { for (var key in obj) { if (hasOwnProp.call(obj, key)) { - fn(key, obj[key]) + fn(key, obj[key]); } } }, assign: function assign (dest, methods) { utils.forEach(methods, function (key, val) { - dest[key] = val - }) + dest[key] = val; + }); } -} +}; function checkType(type) { return function _checkType(val) { - return toString.call(val) === '[object ' + type + ']' - } + return toString.call(val) === '[object ' + type + ']'; + }; } // add isRegExp, isArray, isFunction ['RegExp', 'Array', 'Function'].forEach(function addIsChecks(type) { - utils['is' + type] = checkType(type) -}) + utils['is' + type] = checkType(type); +}); -module.exports = utils +module.exports = utils; diff --git a/package.json b/package.json index a0152d4..141445a 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,11 @@ { "name": "routing-buddy", - "version": "0.2.0", + "version": "0.2.2", "description": "Another router library for both client and server", "main": "lib/router.js", "scripts": { - "test": "mocha --reporter dot && eslint lib/*.js test/*.js" + "lint": "eslint lib/*.js test/*.js", + "test": "mocha --reporter dot && npm run lint" }, "repository": { "type": "git", diff --git a/test/route-node.js b/test/route-node.js index 30b5b56..c7ed9e4 100644 --- a/test/route-node.js +++ b/test/route-node.js @@ -1,91 +1,90 @@ -var expect = require('expect') -var RouteNode = require('../lib/route-node') +var expect = require('expect'); +var RouteNode = require('../lib/route-node'); module.exports = describe('RouteNode', function () { it('→ exists', function () { - expect(new RouteNode()).not.toBeUndefined() - }) + expect(new RouteNode()).toBeInstanceOf(RouteNode); + }); describe('→ add nodes', function () { - var node = null - var callback = function () {} - var context = {} + var node = null; + var callback = function () {}; + var context = {}; beforeEach(function () { - node = new RouteNode() - }) + node = new RouteNode(); + }); it('→ add root node', function (done) { - node.add([], callback, context) + node.add([], callback, context); node.get([], [], function (err, func, cbContext, args) { - expect(err).toBe(null) - expect(func).toBe(callback) - expect(cbContext).toBe(context) - expect(args).toEqual([]) - done() - }) - }) + expect(err).toBe(null); + expect(func).toBe(callback); + expect(cbContext).toBe(context); + expect(args).toEqual([]); + done(); + }); + }); it('→ get nested callback', function (done) { - node.add(['nested'], callback, context) + node.add(['nested'], callback, context); node.get(['nested'], [], function (err, func, cbContext, args) { - expect(err).toBe(null) - expect(func).toBe(callback) - expect(cbContext).toBe(context) - expect(args).toEqual([]) - done() - }) - }) + expect(err).toBe(null); + expect(func).toBe(callback); + expect(cbContext).toBe(context); + expect(args).toEqual([]); + done(); + }); + }); it('→ get error callback for not found', function (done) { node.get(['fake', 'route'], [], function (err, func, cbContext, args) { - expect(err).toBeInstanceOf(Error) - expect(err.message).toMatch(/not found/) - expect(func).toBeUndefined() - expect(cbContext).toBeUndefined() - expect(args).toBeUndefined() - done() - }) - }) + expect(err).toBeInstanceOf(Error); + expect(err.message).toMatch(/not found/); + expect(func).not.toBeDefined(); + expect(cbContext).not.toBeDefined(); + expect(args).toBeUndefined(); + done(); + }); + }); it('→ get route with regex', function (done) { - node.add(['by', 'id', /\d+/], callback, context) + node.add(['by', 'id', /\d+/], callback, context); node.get(['by', 'id', '123'], [], function (err, func, cbContext, args) { - expect(err).toBe(null) - expect(func).toBe(callback) - expect(cbContext).toBe(context) - expect(args).toEqual(['123']) - done() - }) - }) + expect(err).toBe(null); + expect(func).toBe(callback); + expect(cbContext).toBe(context); + expect(args).toEqual(['123']); + done(); + }); + }); it('→ get route with function', function (done) { function toInt(part) { - var results = /^(\d+)$/.exec(part) + var results = /^(\d+)$/.exec(part); if (results) { - return parseInt(results[0], 10) + return parseInt(results[0], 10); } else { - return null + return null; } } - node.add(['by', 'id', toInt], callback, context) + node.add(['by', 'id', toInt], callback, context); node.get(['by', 'id', '123'], [], function (err, func, cbContext, args) { - expect(err).toBe(null, err && err.message) - expect(func).toBe(callback) - expect(cbContext).toBe(context) - expect(args).toEqual([123]) - done() - }) - }) + expect(err).toBe(null, err && err.message); + expect(func).toBe(callback); + expect(cbContext).toBe(context); + expect(args).toEqual([123]); + done(); + }); + }); it('→ pass arguments to handler before parsing', function (done) { - var obj = {} - node.add(['id', /\d+/], callback) + var obj = {}; + node.add(['id', /\d+/], callback); node.get(['id', '123'], [obj], function (err, cb, ctx, args) { - expect(args).toEqual([obj, '123']) - done() - }) - }) - - }) -}) + expect(args).toEqual([obj, '123']); + done(); + }); + }); + }); +}); diff --git a/test/router.js b/test/router.js index 9c54a10..8af7da5 100644 --- a/test/router.js +++ b/test/router.js @@ -1,150 +1,150 @@ -var expect = require('expect') -var Router = require('../lib/router') -var NotFoundError = require('../lib/error').NotFound +var expect = require('expect'); +var Router = require('../lib/router'); +var NotFoundError = require('../lib/error').NotFound; describe('Router', function () { it('→ exists', function () { - expect(Router).not.toBeUndefined() - }) + expect(Router).toBeDefined(); + }); it('→ add root node', function (done) { - var router = new Router() - router.add('/', function () { return 'some value' }) + var router = new Router(); + router.add('/', function () { return 'some value'; }); router.route('/', function (err, handlerResult) { - expect(err).toBe(null) - expect(handlerResult).toBe('some value') - done() - }) - }) + expect(err).toBe(null); + expect(handlerResult).toBe('some value'); + done(); + }); + }); it('→ add/get nested route', function (done) { - var router = new Router() - router.add('/some/path/here', function () { return 'some value' }) + var router = new Router(); + router.add('/some/path/here', function () { return 'some value'; }); router.route('/some/path/here', function (err, handlerResult) { - expect(err).toBe(null) - expect(handlerResult).toBe('some value') - done() - }) - }) + expect(err).toBe(null); + expect(handlerResult).toBe('some value'); + done(); + }); + }); it('→ partial route is a not found error', function (done) { - var router = new Router() - router.add(['/user', /^(\d+)$/], function (number) { return number }) + var router = new Router(); + router.add(['/user', /^(\d+)$/], function (number) { return number; }); router.route('/user/', function (err) { - expect(err).toBeInstanceOf(NotFoundError) - done() - }) - }) + expect(err).toBeInstanceOf(NotFoundError); + done(); + }); + }); it('→ get error in callback for missing handler', function (done) { - var router = new Router() + var router = new Router(); router.route('/some/fake/path', function (err, handlerResult) { - expect(err).toBeInstanceOf(Error) - expect(err.message).toMatch(/not found/) - expect(handlerResult).toBeUndefined() - done() - }) - }) + expect(err).toBeInstanceOf(Error); + expect(err.message).toMatch(/not found/); + expect(handlerResult).not.toBeDefined(); + done(); + }); + }); it('→ get routes based on regex', function (done) { - var router = new Router() + var router = new Router(); router.add(['/by/id', /\d+/], function (someId) { - expect(someId).toBe('123') - }) + expect(someId).toBe('123'); + }); router.route('/by/id/123', function (err) { - expect(err).toBe(null, err && err.message) - done() - }) - }) + expect(err).toBe(null, err && err.message); + done(); + }); + }); it('→ regex routes can return NotFoundError', function (done) { - var router = new Router() - router.add(['/by/id', /\d+/], function () {}) + var router = new Router(); + router.add(['/by/id', /\d+/], function () {}); router.route('/by/id/not-an-id', function (err) { - expect(err).toBeInstanceOf(NotFoundError) - done() - }) - }) + expect(err).toBeInstanceOf(NotFoundError); + done(); + }); + }); it('→ get based on regex with multiple captures global', function (done) { - var router = new Router() + var router = new Router(); router.add(['by', 'order', /(\d+)/g], function (one, two, three) { - expect(one).toBe('1') - expect(two).toBe('2') - expect(three).toBe('3') - }) + expect(one).toBe('1'); + expect(two).toBe('2'); + expect(three).toBe('3'); + }); router.route('/by/order/1-2-3', function (err) { - expect(err).toBe(null, err && err.message) - done() - }) - }) + expect(err).toBe(null, err && err.message); + done(); + }); + }); it('→ get based regex with multiple captures not global', function (done) { - var router = new Router() + var router = new Router(); router.add(['by', 'order', /(\d+)/], function (one, two, three) { - expect(one).toBe('1') - expect(two).toBeUndefined() - expect(three).toBeUndefined() - }) + expect(one).toBe('1'); + expect(two).not.toBeDefined(); + expect(three).not.toBeDefined(); + }); router.route('/by/order/1-2-3', function (err) { - expect(err).toBe(null, err && err.message) - done() - }) - }) + expect(err).toBe(null, err && err.message); + done(); + }); + }); it('→ pass in arguments before capturing path arguments', function (done) { - var router = new Router() - var api = {key: 123, any: 'object is passed', method: function () {}} + var router = new Router(); + var api = {key: 123, any: 'object is passed', method: function () {}}; router.add(['/by/order', /(\d+)/], function (inputApi, urlParam) { - expect(inputApi).toBe(api) - expect(urlParam).toBe('123') - done() - }) + expect(inputApi).toBe(api); + expect(urlParam).toBe('123'); + done(); + }); - router.route('/by/order/123', {args: [api]}) - }) + router.route('/by/order/123', {args: [api]}); + }); function toInt(part) { - var results = /^(\d+)$/.exec(part) + var results = /^(\d+)$/.exec(part); if (results) { - return parseInt(results[0], 10) + return parseInt(results[0], 10); } else { - return null + return null; } } it('→ get based on function', function (done) { - var router = new Router() + var router = new Router(); router.add(['by', 'order', toInt], function (val) { - expect(val).toBe(123) - }) + expect(val).toBe(123); + }); router.route('/by/order/123', function (err) { - expect(err).toBe(null) - done() - }) - }) + expect(err).toBe(null); + done(); + }); + }); it('→ function routes can return NotFoundError', function (done) { - var router = new Router() - router.add(['/by/order', toInt], function () {}) + var router = new Router(); + router.add(['/by/order', toInt], function () {}); router.route('/by/order/not-found', function (err) { - expect(err).toBeInstanceOf(NotFoundError) - done() - }) - }) + expect(err).toBeInstanceOf(NotFoundError); + done(); + }); + }); it('→ check not found error', function (done) { - var router = new Router() + var router = new Router(); router.route('/not/real/id', function (err) { - expect(Router.isNotFound(err)).toBe(true) - done() - }) - }) + expect(Router.isNotFound(err)).toBe(true); + done(); + }); + }); it('→ check not found error on not real error', function () { - expect(Router.isNotFound(new Error('Not the missing error'))).toBe(false) - }) -}) + expect(Router.isNotFound(new Error('Not the missing error'))).toBe(false); + }); +}); diff --git a/test/utils.js b/test/utils.js index d41a8e9..f123284 100644 --- a/test/utils.js +++ b/test/utils.js @@ -1,114 +1,115 @@ -var expect = require('expect') -var utils = require('../lib/utils') +var expect = require('expect'); +var utils = require('../lib/utils'); -var assign = utils.assign -var forEach = utils.forEach -var isArray = utils.isArray -var isFunction = utils.isFunction -var isRegExp = utils.isRegExp -var isString = utils.isString -var noop = utils.noop +var assign = utils.assign; +var forEach = utils.forEach; +var isArray = utils.isArray; +var isFunction = utils.isFunction; +var isRegExp = utils.isRegExp; +var isString = utils.isString; +var noop = utils.noop; function SomeClass (foo) { - this.foo = foo + this.foo = foo; } -SomeClass.prototype.bar = 'asdf' + +SomeClass.prototype.bar = 'asdf'; describe('utils', function () { it('→ exists', function () { - expect(utils).not.toBeUndefined() - }) + expect(utils).not.toBeUndefined(); + }); describe('→ noop', function () { it('→ is a function', function () { - expect(noop).toBeInstanceOf(Function) - }) - }) + expect(noop).toBeInstanceOf(Function); + }); + }); describe('→ isString', function () { it('→ true for strings', function () { - expect(isString('is string')).toBe(true) - }) + expect(isString('is string')).toBe(true); + }); it('→ false for not strings', function () { - expect(isString(/is string/)).toBe(false) - }) - }) + expect(isString(/is string/)).toBe(false); + }); + }); describe('→ isRegExp', function () { it('→ true for regex', function () { - expect(isRegExp(/some regex/)).toBe(true) - }) + expect(isRegExp(/some regex/)).toBe(true); + }); it('→ false for strings', function () { - expect(isRegExp('some string')).toBe(false) - }) - }) + expect(isRegExp('some string')).toBe(false); + }); + }); describe('→ isArray', function () { it('→ true for array', function () { - expect(isArray([])).toBe(true) - }) + expect(isArray([])).toBe(true); + }); it('→ false for regex', function () { - expect(isArray(/some regex/)).toBe(false) - }) + expect(isArray(/some regex/)).toBe(false); + }); it('→ false for strings', function () { - expect(isArray('some string')).toBe(false) - }) - }) + expect(isArray('some string')).toBe(false); + }); + }); describe('→ isFunction', function () { it('→ true for function', function () { - expect(isFunction(function () {})).toBe(true) - }) + expect(isFunction(function () {})).toBe(true); + }); it('→ false for array', function () { - expect(isFunction([])).toBe(false) - }) + expect(isFunction([])).toBe(false); + }); it('→ false for regex', function () { - expect(isFunction(/some regex/)).toBe(false) - }) + expect(isFunction(/some regex/)).toBe(false); + }); it('→ false for strings', function () { - expect(isFunction('some string')).toBe(false) - }) - }) + expect(isFunction('some string')).toBe(false); + }); + }); describe('→ forEach', function () { it('→ does not call properties on prototype', function () { - var count = 0 + var count = 0; forEach(new SomeClass(123), function (key, value) { - count += 1 - expect(key).toBe('foo') - expect(value).toBe(123) - }) - expect(count).toEqual(1) - }) - }) + count += 1; + expect(key).toBe('foo'); + expect(value).toBe(123); + }); + expect(count).toEqual(1); + }); + }); describe('→ assign', function () { it('→ adds properties to dest', function () { - var dest = {} - var src = {foo: 123, bar: 'asdf'} - assign(dest, src) - expect(dest).toEqual({foo: 123, bar: 'asdf'}) - }) + var dest = {}; + var src = {foo: 123, bar: 'asdf'}; + assign(dest, src); + expect(dest).toEqual({foo: 123, bar: 'asdf'}); + }); it('→ overrides properties to dest', function () { - var dest = {foo: 456, bar: 'qwerty', blah: /foo/} - var src = {foo: 123, bar: 'asdf'} - assign(dest, src) - expect(dest).toEqual({foo: 123, bar: 'asdf', blah: /foo/}) - }) + var dest = {foo: 456, bar: 'qwerty', blah: /foo/}; + var src = {foo: 123, bar: 'asdf'}; + assign(dest, src); + expect(dest).toEqual({foo: 123, bar: 'asdf', blah: /foo/}); + }); it('→ does not overrides properties on prototype', function () { - var dest = {foo: 456, bar: 'qwerty', blah: /foo/} - assign(dest, new SomeClass(123)) + var dest = {foo: 456, bar: 'qwerty', blah: /foo/}; + assign(dest, new SomeClass(123)); - expect(dest).toEqual({foo: 123, bar: 'qwerty', blah: /foo/}) - }) - }) -}) + expect(dest).toEqual({foo: 123, bar: 'qwerty', blah: /foo/}); + }); + }); +});