diff --git a/gulpfile.js b/gulpfile.js index e45ac4c..2cbdabc 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,8 +1,10 @@ +/* eslint-disable no-console */ + 'use strict'; -var gulp = require('gulp'), - childProcess = require('child_process'), - jshint = require('gulp-jshint'); +var gulp = require('gulp'); +var childProcess = require('child_process'); +var eslint = require('gulp-eslint'); var realCodePaths = [ '**/*.{js,jsx,coffee}', @@ -12,23 +14,22 @@ var realCodePaths = [ '!docs/**' ]; -gulp.task('lint', function() { +gulp.task('lint', function () { gulp.src(realCodePaths) - .pipe(jshint()) - .pipe(jshint.reporter('jshint-stylish')); + .pipe(eslint()) + .pipe(eslint.format()); }); -gulp.task('jsdoc', function() { +gulp.task('jsdoc', function () { childProcess.exec( './node_modules/.bin/jsdoc -c jsdoc.json', - function(error,stdout,stderr) { + function (error, stdout, stderr) { console.log(stdout); console.error(stderr); } ); }); -gulp.task('default',function() { - gulp.watch(realCodePaths, ['lint','jsdoc']); +gulp.task('default', function () { + gulp.watch(realCodePaths, ['lint', 'jsdoc']); }); - diff --git a/index.js b/index.js index 23274bd..84e14d9 100644 --- a/index.js +++ b/index.js @@ -1,9 +1,9 @@ /** * @module Passage */ + 'use strict'; var Route = require('./lib/route'); - -module.exports = Route; \ No newline at end of file +module.exports = Route; diff --git a/karma.conf.js b/karma.conf.js index d3c2224..6ce7424 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -1,9 +1,9 @@ -/*jshint maxlen:120 */ // Karma configuration // Generated on Sat Feb 15 2014 18:21:16 GMT-0800 (PST) + 'use strict'; -module.exports = function(config) { +module.exports = function (config) { config.set({ // base path, that will be used to resolve files and exclude @@ -49,18 +49,15 @@ module.exports = function(config) { } }, - - // web server port port: 9876, - // enable / disable colors in the output (reporters and logs) colors: true, - // level of logging - // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG + // possible values: config.LOG_DISABLE || config.LOG_ERROR + // || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG logLevel: config.LOG_DEBUG, diff --git a/lib/route.js b/lib/route.js index 7ef1ef3..6acdb77 100644 --- a/lib/route.js +++ b/lib/route.js @@ -1,9 +1,39 @@ 'use strict'; -var Parser = require('./route/parser'), - RegexpVisitor = require('./route/visitors/regexp'), - ReverseVisitor = require('./route/visitors/reverse'); -Route.prototype = Object.create(null) +var Parser = require('./route/parser'); +var RegexpVisitor = require('./route/visitors/regexp'); +var ReverseVisitor = require('./route/visitors/reverse'); + + +/** + * Represents a route + * @example + * var route = Route('/:foo/:bar'); + * @example + * var route = Route('/:foo/:bar'); + * @param {string} spec - the string specification of the route. + * use :param for single portion captures, *param for splat style captures, + * and () for optional route branches + * @constructor + */ +function Route(spec) { + var route; + if (this) { + // constructor called with new + route = this; + } else { + // constructor called as a function + route = Object.create(Route.prototype); + } + if (typeof spec === 'undefined') { + throw new Error('A route spec is required'); + } + route.spec = spec; + route.ast = Parser.parse(spec); + return route; +} + +Route.prototype = Object.create(null); /** * Match a path against this route, returning the matched parameters if @@ -18,12 +48,11 @@ Route.prototype = Object.create(null) * @return {(Object.|false)} A map of the matched route * parameters, or false if matching failed */ -Route.prototype.match = function(path) { - var re = RegexpVisitor.visit(this.ast), - matched = re.match(path); - - return matched ? matched : false; +Route.prototype.match = function (path) { + var re = RegexpVisitor.visit(this.ast); + var matched = re.match(path); + return matched !== null ? matched : false; }; /** @@ -35,36 +64,9 @@ Route.prototype.match = function(path) { * @param {Object} params The parameters to fill in * @return {(String|false)} The filled in path */ -Route.prototype.reverse = function(params) { +Route.prototype.reverse = function (params) { return ReverseVisitor.visit(this.ast, params); }; -/** - * Represents a route - * @example - * var route = Route('/:foo/:bar'); - * @example - * var route = Route('/:foo/:bar'); - * @param {string} spec - the string specification of the route. - * use :param for single portion captures, *param for splat style captures, - * and () for optional route branches - * @constructor - */ -function Route(spec) { - var route; - if (this) { - // constructor called with new - route = this; - } else { - // constructor called as a function - route = Object.create(Route.prototype); - } - if( typeof spec === 'undefined' ) { - throw new Error('A route spec is required'); - } - route.spec = spec; - route.ast = Parser.parse(spec); - return route; -} -module.exports = Route; \ No newline at end of file +module.exports = Route; diff --git a/lib/route/grammar.js b/lib/route/grammar.js index 29503cd..80d0f1d 100644 --- a/lib/route/grammar.js +++ b/lib/route/grammar.js @@ -1,4 +1,5 @@ /** @module route/grammar */ + 'use strict'; /** @@ -12,62 +13,56 @@ * @private */ function o(patternString, action) { - if( typeof action === 'undefined') { + if (typeof action === 'undefined') { return [patternString, '$$ = $1;']; } - else { - action = action.replace(/\bnew /g, '$&yy.'); - return [patternString, '$$ = ' + action + ';']; - } + action = action.replace(/\bnew /g, '$&yy.'); + return [patternString, '$$ = ' + action + ';']; } module.exports = { - 'lex': { - 'rules': [ - ['\\(', 'return "(";' ], - ['\\)', 'return ")";' ], - ['\\*+\\w+', 'return "SPLAT";' ], - [':+\\w+', 'return "PARAM";' ], - ['[\\w%\\-~\\n]+', 'return "LITERAL";' ], - ['.', 'return "LITERAL";' ], - ['$', 'return "EOF";' ] + /* eslint-disable no-multi-spaces */ + lex: { + rules: [ + ['\\(', 'return "(";'], + ['\\)', 'return ")";'], + ['\\*+\\w+', 'return "SPLAT";'], + [':+\\w+', 'return "PARAM";'], + ['[\\w%\\-~\\n]+', 'return "LITERAL";'], + ['.', 'return "LITERAL";'], + ['$', 'return "EOF";'] ] }, - 'bnf': { - 'root': [ + bnf: { + root: [ ['expressions EOF', 'return new yy.Root({},[$1])'], ['EOF', 'return new yy.Root({},[new yy.Literal({value: \'\'})])'] ], - 'expressions': [ + expressions: [ o('expressions expression', 'new Concat({},[$1,$2])'), o('expression') ], - 'expression': [ + expression: [ o('optional'), o('literal', 'new Literal({value: $1})'), o('splat', 'new Splat({name: $1})'), o('param', 'new Param({name: $1})') ], - 'optional': [ + optional: [ o('( expressions )', 'new Optional({},[$2])') ], - 'literal': [ + literal: [ o('LITERAL', 'yytext') ], - 'splat': [ + splat: [ o('SPLAT', 'yytext.slice(1)') ], - 'param': [ + param: [ o('PARAM', 'yytext.slice(1)') ] }, - 'startSymbol': 'root' + startSymbol: 'root' + /* eslint-enable no-multi-spaces */ }; - - -//var parser = new (require('jison').Parser)(grammar); -//parser.yy = require('./nodes'); - -//module.exports = parser; diff --git a/lib/route/nodes.js b/lib/route/nodes.js index 6bb4215..304f940 100644 --- a/lib/route/nodes.js +++ b/lib/route/nodes.js @@ -1,4 +1,5 @@ 'use strict'; + /** @module route/nodes */ @@ -10,7 +11,7 @@ * @return {{displayName: string, props: Object, children: Array}} */ function createNode(displayName) { - return function(props, children) { + return function (props, children) { return { displayName: displayName, props: props, diff --git a/lib/route/parser.js b/lib/route/parser.js index 8732749..438b599 100644 --- a/lib/route/parser.js +++ b/lib/route/parser.js @@ -1,6 +1,7 @@ /** * @module route/parser */ + 'use strict'; /** Wrap the compiled parser with the context to create node objects */ diff --git a/lib/route/visitors/create_visitor.js b/lib/route/visitors/create_visitor.js index 6b5d4a1..72bfdfc 100644 --- a/lib/route/visitors/create_visitor.js +++ b/lib/route/visitors/create_visitor.js @@ -1,4 +1,5 @@ 'use strict'; + /** * @module route/visitors/create_visitor */ @@ -14,11 +15,10 @@ var nodeTypes = Object.keys(require('../nodes')); * method that can be called on a node with a context */ function createVisitor(handlers) { - nodeTypes.forEach(function(nodeType) { - if( typeof handlers[nodeType] === 'undefined') { + nodeTypes.forEach(function (nodeType) { + if (typeof handlers[nodeType] === 'undefined') { throw new Error('No handler defined for ' + nodeType.displayName); } - }); return { @@ -28,8 +28,8 @@ function createVisitor(handlers) { * @param {Object} context context to pass through to handlers * @return {Object} */ - visit: function(node, context) { - return this.handlers[node.displayName].call(this,node, context); + visit: function (node, context) { + return this.handlers[node.displayName].call(this, node, context); }, handlers: handlers }; diff --git a/lib/route/visitors/reconstruct.js b/lib/route/visitors/reconstruct.js index 0bdb22f..57cd6d7 100644 --- a/lib/route/visitors/reconstruct.js +++ b/lib/route/visitors/reconstruct.js @@ -1,6 +1,6 @@ 'use strict'; -var createVisitor = require('./create_visitor'); +var createVisitor = require('./create_visitor'); /** * Visitor for the AST to reconstruct the normalized input @@ -8,33 +8,33 @@ var createVisitor = require('./create_visitor'); * @borrows Visitor-visit */ var ReconstructVisitor = createVisitor({ - 'Concat': function(node) { + Concat: function (node) { return node.children - .map( function(child) { + .map(function (child) { return this.visit(child); }.bind(this)) .join(''); }, - 'Literal': function(node) { + Literal: function (node) { return node.props.value; }, - 'Splat': function(node) { + Splat: function (node) { return '*' + node.props.name; }, - 'Param': function(node) { + Param: function (node) { return ':' + node.props.name; }, - 'Optional': function(node) { + Optional: function (node) { return '(' + this.visit(node.children[0]) + ')'; }, - 'Root': function(node) { + Root: function (node) { return this.visit(node.children[0]); } }); -module.exports = ReconstructVisitor; \ No newline at end of file +module.exports = ReconstructVisitor; diff --git a/lib/route/visitors/regexp.js b/lib/route/visitors/regexp.js index 1b7a938..db8c41e 100644 --- a/lib/route/visitors/regexp.js +++ b/lib/route/visitors/regexp.js @@ -1,7 +1,7 @@ 'use strict'; -var createVisitor = require('./create_visitor'), - escapeRegExp = /[\-{}\[\]+?.,\\\^$|#\s]/g; +var createVisitor = require('./create_visitor'); +var escapeRegExp = /[\-{}\[\]+?.,\\\^$|#\s]/g; /** * @class @@ -18,19 +18,18 @@ function Matcher(options) { * @return {Object|false} matched parameters or false */ Matcher.prototype.match = function (path) { - var match = this.re.exec(path), - matchParams = {}; + var match = this.re.exec(path); + var matchParams = {}; - if( !match ) { - return; + if (!match) { + return false; } - this.captures.forEach( function(capture, i) { - if( typeof match[i+1] === 'undefined' ) { + this.captures.forEach(function (capture, i) { + if (typeof match[i + 1] === 'undefined') { matchParams[capture] = undefined; - } - else { - matchParams[capture] = decodeURIComponent(match[i+1]); + } else { + matchParams[capture] = decodeURIComponent(match[i + 1]); } }); @@ -43,41 +42,41 @@ Matcher.prototype.match = function (path) { * @borrows Visitor-visit */ var RegexpVisitor = createVisitor({ - 'Concat': function(node) { + Concat: function (node) { return node.children .reduce( - function(memo, child) { + function (memo, child) { var childResult = this.visit(child); return { re: memo.re + childResult.re, captures: memo.captures.concat(childResult.captures) }; }.bind(this), - {re: '', captures: []} + { re: '', captures: [] } ); }, - 'Literal': function(node) { + Literal: function (node) { return { re: node.props.value.replace(escapeRegExp, '\\$&'), captures: [] }; }, - 'Splat': function(node) { + Splat: function (node) { return { re: '([^?]*?)', captures: [node.props.name] }; }, - 'Param': function(node) { + Param: function (node) { return { re: '([^\\/\\?]+)', captures: [node.props.name] }; }, - 'Optional': function(node) { + Optional: function (node) { var child = this.visit(node.children[0]); return { re: '(?:' + child.re + ')?', @@ -85,13 +84,13 @@ var RegexpVisitor = createVisitor({ }; }, - 'Root': function(node) { + Root: function (node) { var childResult = this.visit(node.children[0]); return new Matcher({ - re: new RegExp('^' + childResult.re + '(?=\\?|$)' ), + re: new RegExp('^' + childResult.re + '(?=\\?|$)'), captures: childResult.captures }); } }); -module.exports = RegexpVisitor; \ No newline at end of file +module.exports = RegexpVisitor; diff --git a/lib/route/visitors/reverse.js b/lib/route/visitors/reverse.js index ba13cbc..7f517d3 100644 --- a/lib/route/visitors/reverse.js +++ b/lib/route/visitors/reverse.js @@ -1,6 +1,6 @@ 'use strict'; -var createVisitor = require('./create_visitor'); +var createVisitor = require('./create_visitor'); /** * Visitor for the AST to construct a path with filled in parameters @@ -8,56 +8,49 @@ var createVisitor = require('./create_visitor'); * @borrows Visitor-visit */ var ReverseVisitor = createVisitor({ - 'Concat': function(node, context) { - var childResults = node.children - .map( function(child) { - return this.visit(child,context); + Concat: function (node, context) { + var childResults = node.children + .map(function (child) { + return this.visit(child, context); }.bind(this)); - if( childResults.some(function(c) { return c === false; }) ) { + if (childResults.some(function (c) { return c === false; })) { return false; } - else { - return childResults.join(''); - } + return childResults.join(''); }, - 'Literal': function(node) { + Literal: function (node) { return decodeURI(node.props.value); }, - 'Splat': function(node, context) { - if( typeof context[node.props.name] === 'undefined' ) { + Splat: function (node, context) { + if (typeof context[node.props.name] === 'undefined') { return false; } - else { - return context[node.props.name]; - } + return context[node.props.name]; }, - 'Param': function(node, context) { - if( typeof context[node.props.name] === 'undefined' ) { + Param: function (node, context) { + if (typeof context[node.props.name] === 'undefined') { return false; } - else { - return context[node.props.name]; - } + return context[node.props.name]; }, - 'Optional': function(node, context) { + Optional: function (node, context) { var childResult = this.visit(node.children[0], context); - if( childResult ) { + if (childResult) { return childResult; } - else { - return ''; - } + + return ''; }, - 'Root': function(node, context) { + Root: function (node, context) { context = context || {}; var childResult = this.visit(node.children[0], context); - if( childResult === false || typeof childResult === 'undefined' ) { + if (childResult === false || typeof childResult === 'undefined') { return false; } return encodeURI(childResult); diff --git a/scripts/compile_parser.js b/scripts/compile_parser.js index 0e7bf91..909bdf6 100755 --- a/scripts/compile_parser.js +++ b/scripts/compile_parser.js @@ -1,24 +1,26 @@ #!/usr/bin/env node var fs = require('fs'); +var path = require('path'); -var jison = require('jison'), - Lexer = require('jison-lex'), - grammar = require('../lib/route/grammar.js'), - parser = new jison.Parser(grammar); +var jison = require('jison'); +var Lexer = require('jison-lex'); +var grammar = require('../lib/route/grammar.js'); +var parser = new jison.Parser(grammar); +// eslint-disable-next-line no-underscore-dangle parser.lexer = new Lexer(grammar.lex, null, grammar.terminals_); -var compiledGrammar = parser.generate({moduleType: 'js'}); +var compiledGrammar = parser.generate({ moduleType: 'js' }); fs.writeFileSync( - __dirname + '/../lib/route/compiled-grammar.js', + path.join(__dirname, '/../lib/route/compiled-grammar.js'), [ compiledGrammar, "\n\n\nif (typeof require !== 'undefined' && typeof exports !== 'undefined') {", - "\nexports.parser = parser;", - "\nexports.Parser = parser.Parser;", - "\nexports.parse = function () { return parser.parse.apply(parser, arguments); };", - "\n}" + '\nexports.parser = parser;', + '\nexports.Parser = parser.Parser;', + '\nexports.parse = function () { return parser.parse.apply(parser, arguments); };', + '\n}' ].join('') ); diff --git a/test/backbone-compatibility.js b/test/backbone-compatibility.js index 3a0637e..22cae09 100644 --- a/test/backbone-compatibility.js +++ b/test/backbone-compatibility.js @@ -1,62 +1,64 @@ -/*global describe, it */ +/* global describe, it */ + 'use strict'; -var assert = require('chai').assert, - RouteParser = require('../lib/route'); + +var assert = require('chai').assert; +var RouteParser = require('../lib/route'); /* Route, path, expected params, options {name, reversed} */ -var backboneTestCases = [ +var backboneTestCases = [ [ 'search/:query', 'search/news', - {query: 'news'}, - {name: 'simple'} + { query: 'news' }, + { name: 'simple' } ], [ 'search/:query', 'search/тест', - {query: 'тест'}, - {name: 'simple with unicode', reversed: 'search/%D1%82%D0%B5%D1%81%D1%82'} + { query: 'тест' }, + { name: 'simple with unicode', reversed: 'search/%D1%82%D0%B5%D1%81%D1%82' } ], [ 'search/:query/p:page', 'search/nyc/p10', - {query: 'nyc', page: '10'}, - {name: 'two part'} + { query: 'nyc', page: '10' }, + { name: 'two part' } ], [ 'splat/*args/end', 'splat/long-list/of/splatted_99args/end', - {args: 'long-list/of/splatted_99args'}, - {name: 'splats'} + { args: 'long-list/of/splatted_99args' }, + { name: 'splats' } ], [ ':repo/compare/*from...*to', 'backbone/compare/1.0...braddunbar:with/slash', - {repo: 'backbone', from: '1.0', to: 'braddunbar:with/slash'}, - {name: 'complicated mixed'} + { repo: 'backbone', from: '1.0', to: 'braddunbar:with/slash' }, + { name: 'complicated mixed' } ], [ 'optional(/:item)', 'optional', - {item: undefined}, - {name: 'optional'} + { item: undefined }, + { name: 'optional' } ], [ 'optional(/:item)', 'optional/thing', - {item: 'thing'}, - {name: 'optional with param'} + { item: 'thing' }, + { name: 'optional with param' } ], [ '*first/complex-*part/*rest', 'one/two/three/complex-part/four/five/six/seven', - {first: 'one/two/three', part: 'part',rest: 'four/five/six/seven'}, - {name: 'complex'} + { first: 'one/two/three', part: 'part', rest: 'four/five/six/seven' }, + { name: 'complex' } ], [ '*first/complex-*part/*rest', 'has%2Fslash/complex-has%23hash/has%20space', - {first: 'has/slash', part: 'has#hash', rest: 'has space'}, + { first: 'has/slash', part: 'has#hash', rest: 'has space' }, { name: 'backbone#967 decodes encoded values', reversed: 'has/slash/complex-has#hash/has%20space' @@ -65,55 +67,55 @@ var backboneTestCases = [ [ '*anything', 'doesnt-match-a-route', - {anything: 'doesnt-match-a-route'}, - {name: 'anything'} + { anything: 'doesnt-match-a-route' }, + { name: 'anything' } ], [ 'decode/:named/*splat', 'decode/a%2Fb/c%2Fd/e', - {named: 'a/b', splat: 'c/d/e'}, - {name: 'decode named parameters, not splats', reversed: 'decode/a/b/c/d/e'} + { named: 'a/b', splat: 'c/d/e' }, + { name: 'decode named parameters, not splats', reversed: 'decode/a/b/c/d/e' } ], [ 'charñ', 'char%C3%B1', false, - {name: '#2666 - Hashes with UTF8 in them.', reversed: 'char%C3%B1'} + { name: '#2666 - Hashes with UTF8 in them.', reversed: 'char%C3%B1' } ], [ 'charñ', 'charñ', {}, - {name: '#2666 - Hashes with UTF8 in them.', reversed: 'char%C3%B1'} + { name: '#2666 - Hashes with UTF8 in them.', reversed: 'char%C3%B1' } ], [ 'char%C3%B1', 'charñ', false, - {name: '#2666 - Hashes with UTF8 in them.', reversed: 'char%C3%B1'} + { name: '#2666 - Hashes with UTF8 in them.', reversed: 'char%C3%B1' } ], [ 'char%C3%B1', 'char%C3%B1', {}, - {name: '#2666 - Hashes with UTF8 in them.', reversed: 'char%C3%B1'} + { name: '#2666 - Hashes with UTF8 in them.', reversed: 'char%C3%B1' } ], [ '', '', {}, - {name: 'Allows empty route'} + { name: 'Allows empty route' } ], [ 'named/optional/(y:z)', 'named/optional/y', false, - {name: 'doesn\'t match an unfulfilled optional route'} + { name: 'doesn\'t match an unfulfilled optional route' } ], [ 'some/(optional/):thing', 'some/foo', - {thing: 'foo'}, + { thing: 'foo' }, { name: 'backbone#1980 optional with trailing slash', reversed: 'some/optional/foo' @@ -122,36 +124,36 @@ var backboneTestCases = [ [ 'some/(optional/):thing', 'some/optional/foo', - {thing: 'foo'}, - {name: 'backbone#1980 optional with trailing slash'} + { thing: 'foo' }, + { name: 'backbone#1980 optional with trailing slash' } ], [ 'myyjä', 'myyjä', {}, - {name: 'unicode pathname', reversed: 'myyj%C3%A4'} + { name: 'unicode pathname', reversed: 'myyj%C3%A4' } ], [ 'stuff\nnonsense', 'stuff\nnonsense?param=foo%0Abar', {}, - {name: 'newline in route', reversed: 'stuff%0Anonsense'} + { name: 'newline in route', reversed: 'stuff%0Anonsense' } ] -].map( function(testCase) { - var routeSpec = testCase[0], - path = testCase[1], - captured = testCase[2], - name = testCase[3].name, - reversed = testCase[3].reversed || testCase[1]; +].map(function (testCase) { + var routeSpec = testCase[0]; + var path = testCase[1]; + var captured = testCase[2]; + var name = testCase[3].name; + var reversed = testCase[3].reversed || testCase[1]; - return function() { - it(testCase[3].name, function() { + return function () { + it(testCase[3].name, function () { var route = new RouteParser(routeSpec); assert.deepEqual(route.match(path), captured); }); /* Only reverse routes we expected to succeed */ - if( captured ) { - it( 'reverses ' + name, function() { + if (captured) { + it('reverses ' + name, function () { var route = RouteParser(routeSpec); assert.equal(route.reverse(captured), reversed); }); @@ -159,8 +161,8 @@ var backboneTestCases = [ }; }); -describe('Backbone route compatibility', function() { +describe('Backbone route compatibility', function () { for (var i = 0; i < backboneTestCases.length; i++) { backboneTestCases[i](); } -}); \ No newline at end of file +}); diff --git a/test/test.js b/test/test.js index 21263f2..446787e 100644 --- a/test/test.js +++ b/test/test.js @@ -1,169 +1,169 @@ -/*jslint maxlen: 130 */ -/*global describe, it */ +/* global describe, it */ 'use strict'; -var assert = require('chai').assert, - RouteParser = require('../'); +var assert = require('chai').assert; +var RouteParser = require('../'); -describe('Route', function() { - it('should create', function() { + +describe('Route', function () { + it('should create', function () { assert.ok(RouteParser('/foo')); }); - it('should create with new', function() { + it('should create with new', function () { assert.ok(new RouteParser('/foo')); }); - it('should have proper prototype', function() { - var routeInstance = new RouteParser('/foo') + it('should have proper prototype', function () { + var routeInstance = new RouteParser('/foo'); assert.ok(routeInstance instanceof RouteParser); }); - it('should throw on no spec',function() { - assert.throw(function(){ RouteParser(); }, Error, /spec is required/); + it('should throw on no spec', function () { + assert.throw(function () { RouteParser(); }, Error, /spec is required/); }); - describe('basic', function() { - it('should match /foo with a path of /foo', function() { + describe('basic', function () { + it('should match /foo with a path of /foo', function () { var route = RouteParser('/foo'); assert.ok(route.match('/foo')); }); - it('should match /foo with a path of /foo?query',function() { + it('should match /foo with a path of /foo?query', function () { var route = RouteParser('/foo'); assert.ok(route.match('/foo?query')); }); - it('shouldn\'t match /foo with a path of /bar/foo', function() { + it('shouldn\'t match /foo with a path of /bar/foo', function () { var route = RouteParser('/foo'); assert.notOk(route.match('/bar/foo')); }); - it('shouldn\'t match /foo with a path of /foobar', function() { + it('shouldn\'t match /foo with a path of /foobar', function () { var route = RouteParser('/foo'); assert.notOk(route.match('/foobar')); }); - it('shouldn\'t match /foo with a path of /bar', function() { + it('shouldn\'t match /foo with a path of /bar', function () { var route = RouteParser('/foo'); assert.notOk(route.match('/bar')); }); }); - describe('basic parameters', function() { - it('should match /users/:id with a path of /users/1', function() { + describe('basic parameters', function () { + it('should match /users/:id with a path of /users/1', function () { var route = RouteParser('/users/:id'); assert.ok(route.match('/users/1')); }); - it('should not match /users/:id with a path of /users/', function() { + it('should not match /users/:id with a path of /users/', function () { var route = RouteParser('/users/:id'); assert.notOk(route.match('/users/')); }); - it('should match /users/:id with a path of /users/1 and get parameters', function() { + it('should match /users/:id with a path of /users/1 and get parameters', function () { var route = RouteParser('/users/:id'); - assert.deepEqual(route.match('/users/1'), {id: '1'}); + assert.deepEqual(route.match('/users/1'), { id: '1' }); }); - it('should match deep pathing and get parameters', function() { + it('should match deep pathing and get parameters', function () { var route = RouteParser('/users/:id/comments/:comment/rating/:rating'); - assert.deepEqual(route.match('/users/1/comments/cats/rating/22222'), {id: '1', comment: 'cats', rating: '22222'}); + assert.deepEqual(route.match('/users/1/comments/cats/rating/22222'), { id: '1', comment: 'cats', rating: '22222' }); }); }); - describe('splat parameters', function() { - it('should handle double splat parameters', function() { + describe('splat parameters', function () { + it('should handle double splat parameters', function () { var route = RouteParser('/*a/foo/*b'); - assert.deepEqual(route.match('/zoo/woo/foo/bar/baz'), {a: 'zoo/woo', b: 'bar/baz'}); + assert.deepEqual(route.match('/zoo/woo/foo/bar/baz'), { a: 'zoo/woo', b: 'bar/baz' }); }); }); - describe('mixed', function() { - it('should handle mixed splat and named parameters', function() { + describe('mixed', function () { + it('should handle mixed splat and named parameters', function () { var route = RouteParser('/books/*section/:title'); assert.deepEqual( route.match('/books/some/section/last-words-a-memoir'), - {section: 'some/section', title: 'last-words-a-memoir'} + { section: 'some/section', title: 'last-words-a-memoir' } ); }); }); - describe('optional', function() { - it('should allow and match optional routes', function() { + describe('optional', function () { + it('should allow and match optional routes', function () { var route = RouteParser('/users/:id(/style/:style)'); - assert.deepEqual(route.match('/users/3'), {id: '3', style: undefined}); + assert.deepEqual(route.match('/users/3'), { id: '3', style: undefined }); }); - it('should allow and match optional routes', function() { + it('should allow and match optional routes', function () { var route = RouteParser('/users/:id(/style/:style)'); - assert.deepEqual(route.match('/users/3/style/pirate'), {id: '3', style: 'pirate'}); + assert.deepEqual(route.match('/users/3/style/pirate'), { id: '3', style: 'pirate' }); }); - it('allows optional branches that start with a word character', function() { + it('allows optional branches that start with a word character', function () { var route = RouteParser('/things/(option/:first)'); - assert.deepEqual(route.match('/things/option/bar'), {first: 'bar'}); + assert.deepEqual(route.match('/things/option/bar'), { first: 'bar' }); }); - describe('nested', function() { - it('allows nested', function() { + describe('nested', function () { + it('allows nested', function () { var route = RouteParser('/users/:id(/style/:style(/more/:param))'); var result = route.match('/users/3/style/pirate'); - var expected = {id: '3', style: 'pirate', param: undefined}; + var expected = { id: '3', style: 'pirate', param: undefined }; assert.deepEqual(result, expected); }); - it('fetches the correct params from nested', function() { + it('fetches the correct params from nested', function () { var route = RouteParser('/users/:id(/style/:style(/more/:param))'); - assert.deepEqual(route.match('/users/3/style/pirate/more/things'), {id: '3', style: 'pirate', param: 'things'}); + assert.deepEqual(route.match('/users/3/style/pirate/more/things'), { id: '3', style: 'pirate', param: 'things' }); }); }); }); - describe('reverse', function(){ - it('reverses routes without params', function() { + describe('reverse', function () { + it('reverses routes without params', function () { var route = RouteParser('/foo'); - assert.equal(route.reverse(),'/foo'); + assert.equal(route.reverse(), '/foo'); }); - it('reverses routes with simple params', function() { + it('reverses routes with simple params', function () { var route = RouteParser('/:foo/:bar'); - assert.equal(route.reverse({foo: '1', bar: '2'}), '/1/2'); + assert.equal(route.reverse({ foo: '1', bar: '2' }), '/1/2'); }); - it('reverses routes with optional params', function() { + it('reverses routes with optional params', function () { var route = RouteParser('/things/(option/:first)'); - assert.equal(route.reverse({first: 'bar'}), '/things/option/bar'); + assert.equal(route.reverse({ first: 'bar' }), '/things/option/bar'); }); - it('reverses routes with unfilled optional params', function() { + it('reverses routes with unfilled optional params', function () { var route = RouteParser('/things/(option/:first)'); assert.equal(route.reverse(), '/things/'); }); - it('reverses routes with optional params that can\'t fulfill the optional branch', function() { + it('reverses routes with optional params that can\'t fulfill the optional branch', function () { var route = RouteParser('/things/(option/:first(/second/:second))'); - assert.equal(route.reverse({second: 'foo'}), '/things/'); + assert.equal(route.reverse({ second: 'foo' }), '/things/'); }); - it('returns false for routes that can\'t be fulfilled', function() { + it('returns false for routes that can\'t be fulfilled', function () { var route = RouteParser('/foo/:bar'); - assert.equal(route.reverse({}),false); + assert.equal(route.reverse({}), false); }); - it('returns false for routes with splat params that can\'t be fulfilled', function() { + it('returns false for routes with splat params that can\'t be fulfilled', function () { var route = RouteParser('/foo/*bar'); - assert.equal(route.reverse({}),false); + assert.equal(route.reverse({}), false); }); // https://git.io/vPBaA - it('allows reversing falsy valued params', function() { + it('allows reversing falsy valued params', function () { var path = '/account/json/wall/post/:id/comments/?start=:start&max=:max'; var vars = { - id:50, - start:0, - max:12 + id: 50, + start: 0, + max: 12 }; assert.equal( RouteParser(path).reverse(vars), diff --git a/test/visitor.js b/test/visitor.js index ab95d27..0fd1e24 100644 --- a/test/visitor.js +++ b/test/visitor.js @@ -1,42 +1,40 @@ -/*jslint maxlen: 130 */ -/*global describe, it */ +/* global describe, it */ 'use strict'; -var assert = require('chai').assert, - createVisitor = require('../lib/route/visitors/create_visitor'); -function sillyVisitor( node ) { +var assert = require('chai').assert; +var createVisitor = require('../lib/route/visitors/create_visitor'); + +function sillyVisitor(node) { return node.displayName; } -describe('createVisitor', function() { - it('should throw if not all handler node types are defined', function() { - assert.throw(function() { - createVisitor({Root: function(){}}); - }, +describe('createVisitor', function () { + it('should throw if not all handler node types are defined', function () { + assert.throw(function () { + createVisitor({ Root: function () {} }); + }, /No handler defined/ ); }); - it('should create when all handlers are defined',function() { + it('should create when all handlers are defined', function () { var visitor = createVisitor({ - Root: function(node) { return 'Root(' + this.visit(node.children[0]) + ')'; }, - Concat: function(node) { + Root: function (node) { return 'Root(' + this.visit(node.children[0]) + ')'; }, + Concat: function (node) { return 'Concat(' + node.children - .map( function(child) { + .map(function (child) { return this.visit(child); }.bind(this)) .join(' ') + ')'; }, - Optional: function(node) { return 'Optional(' + this.visit(node.children[0]) + ')'; }, + Optional: function (node) { return 'Optional(' + this.visit(node.children[0]) + ')'; }, Literal: sillyVisitor, Splat: sillyVisitor, Param: sillyVisitor }); assert.ok(visitor); - }); }); -