From a99abaa8f103bdd3339692752922398be35cd68f Mon Sep 17 00:00:00 2001 From: Rob Eisenberg Date: Fri, 4 Sep 2015 16:43:25 -0400 Subject: [PATCH] chore(all): prepare release 0.7.0 --- bower.json | 3 +- config.js | 2 +- dist/amd/aurelia-route-recognizer.d.ts | 98 ++---- dist/amd/aurelia-route-recognizer.js | 293 +++++----------- dist/aurelia-route-recognizer.d.ts | 98 ++---- dist/aurelia-route-recognizer.js | 368 ++++++++------------ dist/commonjs/aurelia-route-recognizer.d.ts | 98 ++---- dist/commonjs/aurelia-route-recognizer.js | 297 +++++----------- dist/es6/aurelia-route-recognizer.d.ts | 98 ++---- dist/es6/aurelia-route-recognizer.js | 368 ++++++++------------ dist/system/aurelia-route-recognizer.d.ts | 98 ++---- dist/system/aurelia-route-recognizer.js | 297 +++++----------- doc/CHANGELOG.md | 14 + package.json | 4 +- 14 files changed, 766 insertions(+), 1370 deletions(-) diff --git a/bower.json b/bower.json index 6a0cbde..0589508 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "aurelia-route-recognizer", - "version": "0.6.2", + "version": "0.7.0", "description": "A lightweight JavaScript library that matches paths against registered routes. It includes support for dynamic and star segments and nested handlers.", "keywords": [ "aurelia", @@ -16,6 +16,7 @@ "url": "http://github.com/aurelia/route-recognizer" }, "dependencies": { + "aurelia-path": "^0.9.0", "core-js": "zloirock/core-js" } } diff --git a/config.js b/config.js index 0fbdb84..eaec443 100644 --- a/config.js +++ b/config.js @@ -13,7 +13,7 @@ System.config({ }, map: { - "aurelia-path": "github:aurelia/path@0.8.1", + "aurelia-path": "github:aurelia/path@0.9.0", "babel": "npm:babel-core@5.2.0", "babel-runtime": "npm:babel-runtime@5.2.0", "core-js": "npm:core-js@1.1.3", diff --git a/dist/amd/aurelia-route-recognizer.d.ts b/dist/amd/aurelia-route-recognizer.d.ts index ce4bf91..ef4a9ca 100644 --- a/dist/amd/aurelia-route-recognizer.d.ts +++ b/dist/amd/aurelia-route-recognizer.d.ts @@ -1,5 +1,6 @@ declare module 'aurelia-route-recognizer' { - import * as core from 'core-js'; + import 'core-js'; + import { buildQueryString, parseQueryString } from 'aurelia-path'; export interface RouteHandler { name: string; } @@ -67,7 +68,7 @@ declare module 'aurelia-route-recognizer' { constructor(string: string); eachChar(callback: ((spec: CharSpec) => void)): void; regex(): string; - generate(params: Object, consumed: Object): string; + generate(): string; } export class DynamicSegment { constructor(name: string); @@ -82,84 +83,61 @@ declare module 'aurelia-route-recognizer' { generate(params: Object, consumed: Object): string; } export class EpsilonSegment { - eachChar(callback: ((spec: CharSpec) => void)): void; + eachChar(): void; regex(): string; - generate(params: Object, consumed: Object): string; + generate(): string; } /** - * Class that parses route patterns and matches path strings. - * - * @class RouteRecognizer - * @constructor - */ + * Class that parses route patterns and matches path strings. + * + * @class RouteRecognizer + * @constructor + */ export class RouteRecognizer { constructor(); /** - * Parse a route pattern and add it to the collection of recognized routes. - * - * @method add - * @param {Object} route The route to add. - */ + * Parse a route pattern and add it to the collection of recognized routes. + * + * @param route The route to add. + */ add(route: ConfigurableRoute | ConfigurableRoute[]): State; /** - * Retrieve the handlers registered for the named route. - * - * @method handlersFor - * @param {String} name The name of the route. - * @return {Array} The handlers. - */ + * Retrieve the handlers registered for the named route. + * + * @param name The name of the route. + * @returns The handlers. + */ handlersFor(name: string): HandlerEntry[]; /** - * Check if this RouteRecognizer recognizes a named route. - * - * @method hasRoute - * @param {String} name The name of the route. - * @return {Boolean} True if the named route is recognized. - */ + * Check if this RouteRecognizer recognizes a named route. + * + * @param name The name of the route. + * @returns True if the named route is recognized. + */ hasRoute(name: string): boolean; /** - * Generate a path and query string from a route name and params object. - * - * @method generate - * @param {String} name The name of the route. - * @param {Object} params The route params to use when populating the pattern. - * Properties not required by the pattern will be appended to the query string. - * @return {String} The generated absolute path and query string. - */ + * Generate a path and query string from a route name and params object. + * + * @param name The name of the route. + * @param params The route params to use when populating the pattern. + * Properties not required by the pattern will be appended to the query string. + * @returns The generated absolute path and query string. + */ generate(name: string, params: Object): string; /** - * Generate a query string from an object. - * - * @method generateQueryString - * @param {Object} params Object containing the keys and values to be used. - * @return {String} The generated query string, including leading '?'. - */ - generateQueryString(params: Object): string; - - /** - * Parse a query string. - * - * @method parseQueryString - * @param {String} The query string to parse. - * @return {Object} Object with keys and values mapped from the query string. - */ - parseQueryString(queryString: string): Object; - - /** - * Match a path string against registered route patterns. - * - * @method recognize - * @param {String} path The path to attempt to match. - * @return {Array} Array of objects containing `handler`, `params`, and - * `isDynanic` values for the matched route(s), or undefined if no match - * was found. - */ + * Match a path string against registered route patterns. + * + * @param path The path to attempt to match. + * @returns Array of objects containing `handler`, `params`, and + * `isDynanic` values for the matched route(s), or undefined if no match + * was found. + */ recognize(path: string): RecognizedRoute[]; } class RecognizeResults { diff --git a/dist/amd/aurelia-route-recognizer.js b/dist/amd/aurelia-route-recognizer.js index 560772f..1a1843f 100644 --- a/dist/amd/aurelia-route-recognizer.js +++ b/dist/amd/aurelia-route-recognizer.js @@ -1,4 +1,4 @@ -define(['exports', 'core-js'], function (exports, _coreJs) { +define(['exports', 'core-js', 'aurelia-path'], function (exports, _coreJs, _aureliaPath) { 'use strict'; exports.__esModule = true; @@ -55,23 +55,19 @@ define(['exports', 'core-js'], function (exports, _coreJs) { }; State.prototype.match = function match(ch) { - var nextStates = this.nextStates, - results = [], - child, - charSpec, - chars; + var nextStates = this.nextStates; + var results = []; for (var i = 0, l = nextStates.length; i < l; i++) { - child = nextStates[i]; + var child = nextStates[i]; + var charSpec = child.charSpec; - charSpec = child.charSpec; - - if (typeof (chars = charSpec.validChars) !== 'undefined') { - if (chars.indexOf(ch) !== -1) { + if (charSpec.validChars !== undefined) { + if (charSpec.validChars.indexOf(ch) !== -1) { results.push(child); } - } else if (typeof (chars = charSpec.invalidChars) !== 'undefined') { - if (chars.indexOf(ch) === -1) { + } else if (charSpec.invalidChars !== undefined) { + if (charSpec.invalidChars.indexOf(ch) === -1) { results.push(child); } } @@ -84,7 +80,6 @@ define(['exports', 'core-js'], function (exports, _coreJs) { })(); exports.State = State; - ; var specials = ['/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\']; @@ -120,7 +115,7 @@ define(['exports', 'core-js'], function (exports, _coreJs) { return this.string.replace(escapeRegex, '\\$1'); }; - StaticSegment.prototype.generate = function generate(params, consumed) { + StaticSegment.prototype.generate = function generate() { return this.string; }; @@ -184,13 +179,13 @@ define(['exports', 'core-js'], function (exports, _coreJs) { _classCallCheck(this, EpsilonSegment); } - EpsilonSegment.prototype.eachChar = function eachChar(callback) {}; + EpsilonSegment.prototype.eachChar = function eachChar() {}; EpsilonSegment.prototype.regex = function regex() { return ''; }; - EpsilonSegment.prototype.generate = function generate(params, consumed) { + EpsilonSegment.prototype.generate = function generate() { return ''; }; @@ -208,49 +203,25 @@ define(['exports', 'core-js'], function (exports, _coreJs) { } RouteRecognizer.prototype.add = function add(route) { - if (Array.isArray(route)) { - for (var _iterator3 = route, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) { - var _ref3; - - if (_isArray3) { - if (_i3 >= _iterator3.length) break; - _ref3 = _iterator3[_i3++]; - } else { - _i3 = _iterator3.next(); - if (_i3.done) break; - _ref3 = _i3.value; - } - - var r = _ref3; - - this.add(r); - } - - return; - } - - var currentState = this.rootState, - regex = '^', - types = { statics: 0, dynamics: 0, stars: 0 }, - names = [], - routeName = route.handler.name, - isEmpty = true; + var _this = this; + if (Array.isArray(route)) { + route.forEach(function (r) { + return _this.add(r); + }); + return undefined; + } + + var currentState = this.rootState; + var regex = '^'; + var types = { statics: 0, dynamics: 0, stars: 0 }; + var names = []; + var routeName = route.handler.name; + var isEmpty = true; var segments = parse(route.path, names, types); - for (var _iterator4 = segments, _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();;) { - var _ref4; - - if (_isArray4) { - if (_i4 >= _iterator4.length) break; - _ref4 = _iterator4[_i4++]; - } else { - _i4 = _iterator4.next(); - if (_i4.done) break; - _ref4 = _i4.value; - } - - var segment = _ref4; + for (var i = 0, ii = segments.length; i < ii; i++) { + var segment = segments[i]; if (segment instanceof EpsilonSegment) { continue; } @@ -286,18 +257,12 @@ define(['exports', 'core-js'], function (exports, _coreJs) { }; RouteRecognizer.prototype.handlersFor = function handlersFor(name) { - var route = this.names[name], - result = []; - + var route = this.names[name]; if (!route) { throw new Error('There is no route named ' + name); } - for (var i = 0, l = route.handlers.length; i < l; i++) { - result.push(route.handlers[i]); - } - - return result; + return [].concat(route.handlers); }; RouteRecognizer.prototype.hasRoute = function hasRoute(name) { @@ -305,17 +270,16 @@ define(['exports', 'core-js'], function (exports, _coreJs) { }; RouteRecognizer.prototype.generate = function generate(name, params) { - params = Object.assign({}, params); - - var route = this.names[name], - consumed = {}, - output = ''; + var routeParams = Object.assign({}, params); + var route = this.names[name]; if (!route) { throw new Error('There is no route named ' + name); } var segments = route.segments; + var consumed = {}; + var output = ''; for (var i = 0, l = segments.length; i < l; i++) { var segment = segments[i]; @@ -325,7 +289,7 @@ define(['exports', 'core-js'], function (exports, _coreJs) { } output += '/'; - var segmentValue = segment.generate(params, consumed); + var segmentValue = segment.generate(routeParams, consumed); if (segmentValue === null || segmentValue === undefined) { throw new Error('A value is required for route parameter \'' + segment.name + '\' in route \'' + name + '\'.'); } @@ -338,131 +302,49 @@ define(['exports', 'core-js'], function (exports, _coreJs) { } for (var param in consumed) { - delete params[param]; + delete routeParams[param]; } - output += this.generateQueryString(params); + var queryString = _aureliaPath.buildQueryString(routeParams); + output += queryString ? '?' + queryString : ''; return output; }; - RouteRecognizer.prototype.generateQueryString = function generateQueryString(params) { - var pairs = [], - keys = [], - encode = encodeURIComponent, - encodeKey = function encodeKey(k) { - return encode(k).replace('%24', '$'); - }; - - for (var key in params) { - if (params.hasOwnProperty(key)) { - keys.push(key); - } - } - - keys.sort(); - for (var i = 0, len = keys.length; i < len; i++) { - key = keys[i]; - var value = params[key]; - if (value === null || value === undefined) { - continue; - } - - if (Array.isArray(value)) { - var arrayKey = encodeKey(key) + '[]'; - for (var j = 0, l = value.length; j < l; j++) { - pairs.push(arrayKey + '=' + encode(value[j])); - } - } else { - pairs.push(encodeKey(key) + '=' + encode(value)); - } - } - - if (pairs.length === 0) { - return ''; - } - - return '?' + pairs.join('&'); - }; - - RouteRecognizer.prototype.parseQueryString = function parseQueryString(queryString) { + RouteRecognizer.prototype.recognize = function recognize(path) { + var states = [this.rootState]; var queryParams = {}; - if (!queryString || typeof queryString !== 'string') { - return queryParams; - } - - if (queryString.charAt(0) === '?') { - queryString = queryString.substr(1); - } + var isSlashDropped = false; + var normalizedPath = path; - var pairs = queryString.split('&'); - for (var i = 0; i < pairs.length; i++) { - var pair = pairs[i].split('='), - key = decodeURIComponent(pair[0]), - keyLength = key.length, - isArray = false, - value; - - if (!key) { - continue; - } else if (pair.length === 1) { - value = true; - } else { - if (keyLength > 2 && key.slice(keyLength - 2) === '[]') { - isArray = true; - key = key.slice(0, keyLength - 2); - if (!queryParams[key]) { - queryParams[key] = []; - } - } - value = pair[1] ? decodeURIComponent(pair[1]) : ''; - } - if (isArray) { - queryParams[key].push(value); - } else { - queryParams[key] = value; - } - } - return queryParams; - }; - - RouteRecognizer.prototype.recognize = function recognize(path) { - var states = [this.rootState], - pathLen, - i, - l, - queryStart, - queryParams = {}, - isSlashDropped = false; - - queryStart = path.indexOf('?'); + var queryStart = normalizedPath.indexOf('?'); if (queryStart !== -1) { - var queryString = path.substr(queryStart + 1, path.length); - path = path.substr(0, queryStart); - queryParams = this.parseQueryString(queryString); + var queryString = normalizedPath.substr(queryStart + 1, normalizedPath.length); + normalizedPath = normalizedPath.substr(0, queryStart); + queryParams = _aureliaPath.parseQueryString(queryString); } - path = decodeURI(path); + normalizedPath = decodeURI(normalizedPath); - if (path.charAt(0) !== '/') { - path = '/' + path; + if (normalizedPath.charAt(0) !== '/') { + normalizedPath = '/' + normalizedPath; } - pathLen = path.length; - if (pathLen > 1 && path.charAt(pathLen - 1) === '/') { - path = path.substr(0, pathLen - 1); + var pathLen = normalizedPath.length; + if (pathLen > 1 && normalizedPath.charAt(pathLen - 1) === '/') { + normalizedPath = normalizedPath.substr(0, pathLen - 1); isSlashDropped = true; } - for (i = 0, l = path.length; i < l; i++) { - states = recognizeChar(states, path.charAt(i)); + for (var i = 0, l = normalizedPath.length; i < l; i++) { + states = recognizeChar(states, normalizedPath.charAt(i)); if (!states.length) { break; } } var solutions = []; - for (i = 0, l = states.length; i < l; i++) { + for (var i = 0, l = states.length; i < l; i++) { if (states[i].handlers) { solutions.push(states[i]); } @@ -473,9 +355,10 @@ define(['exports', 'core-js'], function (exports, _coreJs) { var state = solutions[0]; if (state && state.handlers) { if (isSlashDropped && state.regex.source.slice(-5) === '(.+)$') { - path = path + '/'; + normalizedPath = normalizedPath + '/'; } - return findHandler(state, path, queryParams); + + return findHandler(state, normalizedPath, queryParams); } }; @@ -495,33 +378,37 @@ define(['exports', 'core-js'], function (exports, _coreJs) { }; function parse(route, names, types) { + var normalizedRoute = route; if (route.charAt(0) === '/') { - route = route.substr(1); + normalizedRoute = route.substr(1); } var results = []; - for (var _iterator5 = route.split('/'), _isArray5 = Array.isArray(_iterator5), _i5 = 0, _iterator5 = _isArray5 ? _iterator5 : _iterator5[Symbol.iterator]();;) { - var _ref5; + for (var _iterator3 = normalizedRoute.split('/'), _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) { + var _ref3; - if (_isArray5) { - if (_i5 >= _iterator5.length) break; - _ref5 = _iterator5[_i5++]; + if (_isArray3) { + if (_i3 >= _iterator3.length) break; + _ref3 = _iterator3[_i3++]; } else { - _i5 = _iterator5.next(); - if (_i5.done) break; - _ref5 = _i5.value; + _i3 = _iterator3.next(); + if (_i3.done) break; + _ref3 = _i3.value; } - var segment = _ref5; - - var match = undefined; + var segment = _ref3; - if (match = segment.match(/^:([^\/]+)$/)) { + var match = segment.match(/^:([^\/]+)$/); + if (match) { results.push(new DynamicSegment(match[1])); names.push(match[1]); types.dynamics++; - } else if (match = segment.match(/^\*([^\/]+)$/)) { + continue; + } + + match = segment.match(/^\*([^\/]+)$/); + if (match) { results.push(new StarSegment(match[1])); names.push(match[1]); types.stars++; @@ -568,40 +455,40 @@ define(['exports', 'core-js'], function (exports, _coreJs) { for (var i = 0, l = states.length; i < l; i++) { var state = states[i]; - - nextStates = nextStates.concat(state.match(ch)); + nextStates.push.apply(nextStates, state.match(ch)); } return nextStates; } function findHandler(state, path, queryParams) { - var handlers = state.handlers, - regex = state.regex; - var captures = path.match(regex), - currentCapture = 1; + var handlers = state.handlers; + var regex = state.regex; + var captures = path.match(regex); + var currentCapture = 1; var result = new RecognizeResults(queryParams); for (var i = 0, l = handlers.length; i < l; i++) { - var handler = handlers[i], - names = handler.names, - params = {}; + var _handler = handlers[i]; + var _names = _handler.names; + var _params = {}; - for (var j = 0, m = names.length; j < m; j++) { - params[names[j]] = captures[currentCapture++]; + for (var j = 0, m = _names.length; j < m; j++) { + _params[_names[j]] = captures[currentCapture++]; } - result.push({ handler: handler.handler, params: params, isDynamic: !!names.length }); + result.push({ handler: _handler.handler, params: _params, isDynamic: !!_names.length }); } return result; } function addSegment(currentState, segment) { + var state = currentState; segment.eachChar(function (ch) { - currentState = currentState.put(ch); + state = state.put(ch); }); - return currentState; + return state; } }); \ No newline at end of file diff --git a/dist/aurelia-route-recognizer.d.ts b/dist/aurelia-route-recognizer.d.ts index ce4bf91..ef4a9ca 100644 --- a/dist/aurelia-route-recognizer.d.ts +++ b/dist/aurelia-route-recognizer.d.ts @@ -1,5 +1,6 @@ declare module 'aurelia-route-recognizer' { - import * as core from 'core-js'; + import 'core-js'; + import { buildQueryString, parseQueryString } from 'aurelia-path'; export interface RouteHandler { name: string; } @@ -67,7 +68,7 @@ declare module 'aurelia-route-recognizer' { constructor(string: string); eachChar(callback: ((spec: CharSpec) => void)): void; regex(): string; - generate(params: Object, consumed: Object): string; + generate(): string; } export class DynamicSegment { constructor(name: string); @@ -82,84 +83,61 @@ declare module 'aurelia-route-recognizer' { generate(params: Object, consumed: Object): string; } export class EpsilonSegment { - eachChar(callback: ((spec: CharSpec) => void)): void; + eachChar(): void; regex(): string; - generate(params: Object, consumed: Object): string; + generate(): string; } /** - * Class that parses route patterns and matches path strings. - * - * @class RouteRecognizer - * @constructor - */ + * Class that parses route patterns and matches path strings. + * + * @class RouteRecognizer + * @constructor + */ export class RouteRecognizer { constructor(); /** - * Parse a route pattern and add it to the collection of recognized routes. - * - * @method add - * @param {Object} route The route to add. - */ + * Parse a route pattern and add it to the collection of recognized routes. + * + * @param route The route to add. + */ add(route: ConfigurableRoute | ConfigurableRoute[]): State; /** - * Retrieve the handlers registered for the named route. - * - * @method handlersFor - * @param {String} name The name of the route. - * @return {Array} The handlers. - */ + * Retrieve the handlers registered for the named route. + * + * @param name The name of the route. + * @returns The handlers. + */ handlersFor(name: string): HandlerEntry[]; /** - * Check if this RouteRecognizer recognizes a named route. - * - * @method hasRoute - * @param {String} name The name of the route. - * @return {Boolean} True if the named route is recognized. - */ + * Check if this RouteRecognizer recognizes a named route. + * + * @param name The name of the route. + * @returns True if the named route is recognized. + */ hasRoute(name: string): boolean; /** - * Generate a path and query string from a route name and params object. - * - * @method generate - * @param {String} name The name of the route. - * @param {Object} params The route params to use when populating the pattern. - * Properties not required by the pattern will be appended to the query string. - * @return {String} The generated absolute path and query string. - */ + * Generate a path and query string from a route name and params object. + * + * @param name The name of the route. + * @param params The route params to use when populating the pattern. + * Properties not required by the pattern will be appended to the query string. + * @returns The generated absolute path and query string. + */ generate(name: string, params: Object): string; /** - * Generate a query string from an object. - * - * @method generateQueryString - * @param {Object} params Object containing the keys and values to be used. - * @return {String} The generated query string, including leading '?'. - */ - generateQueryString(params: Object): string; - - /** - * Parse a query string. - * - * @method parseQueryString - * @param {String} The query string to parse. - * @return {Object} Object with keys and values mapped from the query string. - */ - parseQueryString(queryString: string): Object; - - /** - * Match a path string against registered route patterns. - * - * @method recognize - * @param {String} path The path to attempt to match. - * @return {Array} Array of objects containing `handler`, `params`, and - * `isDynanic` values for the matched route(s), or undefined if no match - * was found. - */ + * Match a path string against registered route patterns. + * + * @param path The path to attempt to match. + * @returns Array of objects containing `handler`, `params`, and + * `isDynanic` values for the matched route(s), or undefined if no match + * was found. + */ recognize(path: string): RecognizedRoute[]; } class RecognizeResults { diff --git a/dist/aurelia-route-recognizer.js b/dist/aurelia-route-recognizer.js index b8937e2..a35f16c 100644 --- a/dist/aurelia-route-recognizer.js +++ b/dist/aurelia-route-recognizer.js @@ -1,4 +1,5 @@ -import * as core from 'core-js'; +import 'core-js'; +import {buildQueryString,parseQueryString} from 'aurelia-path'; // A State has a character specification and (`charSpec`) and a list of possible // subsequent states (`nextStates`). @@ -25,8 +26,8 @@ export class State { get(charSpec: CharSpec): State { for (let child of this.nextStates) { - var isEqual = child.charSpec.validChars === charSpec.validChars && - child.charSpec.invalidChars === charSpec.invalidChars; + let isEqual = child.charSpec.validChars === charSpec.validChars + && child.charSpec.invalidChars === charSpec.invalidChars; if (isEqual) { return child; @@ -35,7 +36,7 @@ export class State { } put(charSpec: CharSpec): State { - var state = this.get(charSpec); + let state = this.get(charSpec); // If the character specification already exists in a child of the current // state, just return that state. @@ -62,20 +63,19 @@ export class State { // Find a list of child states matching the next character match(ch: string): State[] { - var nextStates = this.nextStates, results = [], - child, charSpec, chars; + let nextStates = this.nextStates; + let results = []; - for (var i = 0, l = nextStates.length; i < l; i++) { - child = nextStates[i]; + for (let i = 0, l = nextStates.length; i < l; i++) { + let child = nextStates[i]; + let charSpec = child.charSpec; - charSpec = child.charSpec; - - if (typeof (chars = charSpec.validChars) !== 'undefined') { - if (chars.indexOf(ch) !== -1) { + if (charSpec.validChars !== undefined) { + if (charSpec.validChars.indexOf(ch) !== -1) { results.push(child); } - } else if (typeof (chars = charSpec.invalidChars) !== 'undefined') { - if (chars.indexOf(ch) === -1) { + } else if (charSpec.invalidChars !== undefined) { + if (charSpec.invalidChars.indexOf(ch) === -1) { results.push(child); } } @@ -83,7 +83,7 @@ export class State { return results; } -}; +} const specials = [ '/', '.', '*', '+', '?', '|', @@ -110,11 +110,11 @@ const escapeRegex = new RegExp('(\\' + specials.join('|\\') + ')', 'g'); // * `repeat`: true if the character specification can repeat export class StaticSegment { - constructor(string:string) { + constructor(string: string) { this.string = string; } - eachChar(callback: (spec:CharSpec) => void): void { + eachChar(callback: (spec: CharSpec) => void): void { for (let ch of this.string) { callback({ validChars: ch }); } @@ -124,7 +124,7 @@ export class StaticSegment { return this.string.replace(escapeRegex, '\\$1'); } - generate(params:Object, consumed:Object): string { + generate(): string { return this.string; } } @@ -134,7 +134,7 @@ export class DynamicSegment { this.name = name; } - eachChar(callback:(spec :CharSpec) => void): void { + eachChar(callback: (spec: CharSpec) => void): void { callback({ invalidChars: '/', repeat: true }); } @@ -153,7 +153,7 @@ export class StarSegment { this.name = name; } - eachChar(callback: (spec:CharSpec) => void): void { + eachChar(callback: (spec: CharSpec) => void): void { callback({ invalidChars: '', repeat: true }); } @@ -168,9 +168,16 @@ export class StarSegment { } export class EpsilonSegment { - eachChar(callback: (spec:CharSpec) => void): void {} - regex(): string { return ''; } - generate(params: Object, consumed: Object): string { return ''; } + eachChar(): void { + } + + regex(): string { + return ''; + } + + generate(): string { + return ''; + } } interface RouteHandler { @@ -200,11 +207,11 @@ interface CharSpec { } /** - * Class that parses route patterns and matches path strings. - * - * @class RouteRecognizer - * @constructor - */ +* Class that parses route patterns and matches path strings. +* +* @class RouteRecognizer +* @constructor +*/ export class RouteRecognizer { constructor() { this.rootState = new State(); @@ -212,27 +219,26 @@ export class RouteRecognizer { } /** - * Parse a route pattern and add it to the collection of recognized routes. - * - * @method add - * @param {Object} route The route to add. - */ + * Parse a route pattern and add it to the collection of recognized routes. + * + * @param route The route to add. + */ add(route: ConfigurableRoute|ConfigurableRoute[]): State { if (Array.isArray(route)) { - for (let r of route) { - this.add(r); - } - - return; + route.forEach(r => this.add(r)); + return undefined; } - var currentState = this.rootState, regex = '^', - types = { statics: 0, dynamics: 0, stars: 0 }, - names = [], routeName = route.handler.name, - isEmpty = true; + let currentState = this.rootState; + let regex = '^'; + let types = { statics: 0, dynamics: 0, stars: 0 }; + let names = []; + let routeName = route.handler.name; + let isEmpty = true; + let segments = parse(route.path, names, types); - var segments = parse(route.path, names, types); - for (let segment of segments) { + for (let i = 0, ii = segments.length; i < ii; i++) { + let segment = segments[i]; if (segment instanceof EpsilonSegment) { continue; } @@ -253,7 +259,7 @@ export class RouteRecognizer { regex += '/'; } - var handlers = [{ handler: route.handler, names: names }]; + let handlers = [{ handler: route.handler, names: names }]; if (routeName) { this.names[routeName] = { @@ -270,68 +276,59 @@ export class RouteRecognizer { } /** - * Retrieve the handlers registered for the named route. - * - * @method handlersFor - * @param {String} name The name of the route. - * @return {Array} The handlers. - */ + * Retrieve the handlers registered for the named route. + * + * @param name The name of the route. + * @returns The handlers. + */ handlersFor(name: string): HandlerEntry[] { - var route = this.names[name], - result = []; - + let route = this.names[name]; if (!route) { throw new Error(`There is no route named ${name}`); } - for (var i=0, l=route.handlers.length; i encode(k).replace('%24', '$'); - - for (var key in params) { - if (params.hasOwnProperty(key)) { - keys.push(key); - } - } - - keys.sort(); - for (var i = 0, len = keys.length; i < len; i++) { - key = keys[i]; - var value = params[key]; - if (value === null || value === undefined) { - continue; - } - - if (Array.isArray(value)) { - var arrayKey = `${encodeKey(key)}[]`; - for (var j = 0, l = value.length; j < l; j++) { - pairs.push(`${arrayKey}=${encode(value[j])}`); - } - } else { - pairs.push(`${encodeKey(key)}=${encode(value)}`); - } - } - - if (pairs.length === 0) { - return ''; - } - - return '?' + pairs.join('&'); - } - - /** - * Parse a query string. - * - * @method parseQueryString - * @param {String} The query string to parse. - * @return {Object} Object with keys and values mapped from the query string. - */ - parseQueryString(queryString: string): Object { - var queryParams = {}; - if (!queryString || typeof queryString !== 'string') { - return queryParams; - } - - if (queryString.charAt(0) === '?') { - queryString = queryString.substr(1); - } - - var pairs = queryString.split('&'); - for(var i = 0; i < pairs.length; i++) { - var pair = pairs[i].split('='), - key = decodeURIComponent(pair[0]), - keyLength = key.length, - isArray = false, - value; - - if (!key) { - continue; - } else if (pair.length === 1) { - value = true; - } else { - //Handle arrays - if (keyLength > 2 && key.slice(keyLength -2) === '[]') { - isArray = true; - key = key.slice(0, keyLength - 2); - if(!queryParams[key]) { - queryParams[key] = []; - } - } - value = pair[1] ? decodeURIComponent(pair[1]) : ''; - } - if (isArray) { - queryParams[key].push(value); - } else { - queryParams[key] = value; - } - } - return queryParams; - } - - /** - * Match a path string against registered route patterns. - * - * @method recognize - * @param {String} path The path to attempt to match. - * @return {Array} Array of objects containing `handler`, `params`, and - * `isDynanic` values for the matched route(s), or undefined if no match - * was found. - */ + * Match a path string against registered route patterns. + * + * @param path The path to attempt to match. + * @returns Array of objects containing `handler`, `params`, and + * `isDynanic` values for the matched route(s), or undefined if no match + * was found. + */ recognize(path: string): RecognizedRoute[] { - var states = [ this.rootState ], - pathLen, i, l, queryStart, queryParams = {}, - isSlashDropped = false; + let states = [this.rootState]; + let queryParams = {}; + let isSlashDropped = false; + let normalizedPath = path; - queryStart = path.indexOf('?'); + let queryStart = normalizedPath.indexOf('?'); if (queryStart !== -1) { - var queryString = path.substr(queryStart + 1, path.length); - path = path.substr(0, queryStart); - queryParams = this.parseQueryString(queryString); + let queryString = normalizedPath.substr(queryStart + 1, normalizedPath.length); + normalizedPath = normalizedPath.substr(0, queryStart); + queryParams = parseQueryString(queryString); } - path = decodeURI(path); + normalizedPath = decodeURI(normalizedPath); - if (path.charAt(0) !== '/') { - path = '/' + path; + if (normalizedPath.charAt(0) !== '/') { + normalizedPath = '/' + normalizedPath; } - pathLen = path.length; - if (pathLen > 1 && path.charAt(pathLen - 1) === '/') { - path = path.substr(0, pathLen - 1); + let pathLen = normalizedPath.length; + if (pathLen > 1 && normalizedPath.charAt(pathLen - 1) === '/') { + normalizedPath = normalizedPath.substr(0, pathLen - 1); isSlashDropped = true; } - for (i = 0, l = path.length; i < l; i++) { - states = recognizeChar(states, path.charAt(i)); + for (let i = 0, l = normalizedPath.length; i < l; i++) { + states = recognizeChar(states, normalizedPath.charAt(i)); if (!states.length) { break; } } - var solutions = []; - for (i=0, l=states.length; i { - currentState = currentState.put(ch); + state = state.put(ch); }); - return currentState; + return state; } diff --git a/dist/commonjs/aurelia-route-recognizer.d.ts b/dist/commonjs/aurelia-route-recognizer.d.ts index ce4bf91..ef4a9ca 100644 --- a/dist/commonjs/aurelia-route-recognizer.d.ts +++ b/dist/commonjs/aurelia-route-recognizer.d.ts @@ -1,5 +1,6 @@ declare module 'aurelia-route-recognizer' { - import * as core from 'core-js'; + import 'core-js'; + import { buildQueryString, parseQueryString } from 'aurelia-path'; export interface RouteHandler { name: string; } @@ -67,7 +68,7 @@ declare module 'aurelia-route-recognizer' { constructor(string: string); eachChar(callback: ((spec: CharSpec) => void)): void; regex(): string; - generate(params: Object, consumed: Object): string; + generate(): string; } export class DynamicSegment { constructor(name: string); @@ -82,84 +83,61 @@ declare module 'aurelia-route-recognizer' { generate(params: Object, consumed: Object): string; } export class EpsilonSegment { - eachChar(callback: ((spec: CharSpec) => void)): void; + eachChar(): void; regex(): string; - generate(params: Object, consumed: Object): string; + generate(): string; } /** - * Class that parses route patterns and matches path strings. - * - * @class RouteRecognizer - * @constructor - */ + * Class that parses route patterns and matches path strings. + * + * @class RouteRecognizer + * @constructor + */ export class RouteRecognizer { constructor(); /** - * Parse a route pattern and add it to the collection of recognized routes. - * - * @method add - * @param {Object} route The route to add. - */ + * Parse a route pattern and add it to the collection of recognized routes. + * + * @param route The route to add. + */ add(route: ConfigurableRoute | ConfigurableRoute[]): State; /** - * Retrieve the handlers registered for the named route. - * - * @method handlersFor - * @param {String} name The name of the route. - * @return {Array} The handlers. - */ + * Retrieve the handlers registered for the named route. + * + * @param name The name of the route. + * @returns The handlers. + */ handlersFor(name: string): HandlerEntry[]; /** - * Check if this RouteRecognizer recognizes a named route. - * - * @method hasRoute - * @param {String} name The name of the route. - * @return {Boolean} True if the named route is recognized. - */ + * Check if this RouteRecognizer recognizes a named route. + * + * @param name The name of the route. + * @returns True if the named route is recognized. + */ hasRoute(name: string): boolean; /** - * Generate a path and query string from a route name and params object. - * - * @method generate - * @param {String} name The name of the route. - * @param {Object} params The route params to use when populating the pattern. - * Properties not required by the pattern will be appended to the query string. - * @return {String} The generated absolute path and query string. - */ + * Generate a path and query string from a route name and params object. + * + * @param name The name of the route. + * @param params The route params to use when populating the pattern. + * Properties not required by the pattern will be appended to the query string. + * @returns The generated absolute path and query string. + */ generate(name: string, params: Object): string; /** - * Generate a query string from an object. - * - * @method generateQueryString - * @param {Object} params Object containing the keys and values to be used. - * @return {String} The generated query string, including leading '?'. - */ - generateQueryString(params: Object): string; - - /** - * Parse a query string. - * - * @method parseQueryString - * @param {String} The query string to parse. - * @return {Object} Object with keys and values mapped from the query string. - */ - parseQueryString(queryString: string): Object; - - /** - * Match a path string against registered route patterns. - * - * @method recognize - * @param {String} path The path to attempt to match. - * @return {Array} Array of objects containing `handler`, `params`, and - * `isDynanic` values for the matched route(s), or undefined if no match - * was found. - */ + * Match a path string against registered route patterns. + * + * @param path The path to attempt to match. + * @returns Array of objects containing `handler`, `params`, and + * `isDynanic` values for the matched route(s), or undefined if no match + * was found. + */ recognize(path: string): RecognizedRoute[]; } class RecognizeResults { diff --git a/dist/commonjs/aurelia-route-recognizer.js b/dist/commonjs/aurelia-route-recognizer.js index a785d34..f3177b8 100644 --- a/dist/commonjs/aurelia-route-recognizer.js +++ b/dist/commonjs/aurelia-route-recognizer.js @@ -2,13 +2,11 @@ exports.__esModule = true; -function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } - function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } -var _coreJs = require('core-js'); +require('core-js'); -var core = _interopRequireWildcard(_coreJs); +var _aureliaPath = require('aurelia-path'); var State = (function () { function State(charSpec) { @@ -60,23 +58,19 @@ var State = (function () { }; State.prototype.match = function match(ch) { - var nextStates = this.nextStates, - results = [], - child, - charSpec, - chars; + var nextStates = this.nextStates; + var results = []; for (var i = 0, l = nextStates.length; i < l; i++) { - child = nextStates[i]; - - charSpec = child.charSpec; + var child = nextStates[i]; + var charSpec = child.charSpec; - if (typeof (chars = charSpec.validChars) !== 'undefined') { - if (chars.indexOf(ch) !== -1) { + if (charSpec.validChars !== undefined) { + if (charSpec.validChars.indexOf(ch) !== -1) { results.push(child); } - } else if (typeof (chars = charSpec.invalidChars) !== 'undefined') { - if (chars.indexOf(ch) === -1) { + } else if (charSpec.invalidChars !== undefined) { + if (charSpec.invalidChars.indexOf(ch) === -1) { results.push(child); } } @@ -89,7 +83,6 @@ var State = (function () { })(); exports.State = State; -; var specials = ['/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\']; @@ -125,7 +118,7 @@ var StaticSegment = (function () { return this.string.replace(escapeRegex, '\\$1'); }; - StaticSegment.prototype.generate = function generate(params, consumed) { + StaticSegment.prototype.generate = function generate() { return this.string; }; @@ -189,13 +182,13 @@ var EpsilonSegment = (function () { _classCallCheck(this, EpsilonSegment); } - EpsilonSegment.prototype.eachChar = function eachChar(callback) {}; + EpsilonSegment.prototype.eachChar = function eachChar() {}; EpsilonSegment.prototype.regex = function regex() { return ''; }; - EpsilonSegment.prototype.generate = function generate(params, consumed) { + EpsilonSegment.prototype.generate = function generate() { return ''; }; @@ -213,49 +206,25 @@ var RouteRecognizer = (function () { } RouteRecognizer.prototype.add = function add(route) { - if (Array.isArray(route)) { - for (var _iterator3 = route, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) { - var _ref3; - - if (_isArray3) { - if (_i3 >= _iterator3.length) break; - _ref3 = _iterator3[_i3++]; - } else { - _i3 = _iterator3.next(); - if (_i3.done) break; - _ref3 = _i3.value; - } - - var r = _ref3; - - this.add(r); - } - - return; - } - - var currentState = this.rootState, - regex = '^', - types = { statics: 0, dynamics: 0, stars: 0 }, - names = [], - routeName = route.handler.name, - isEmpty = true; + var _this = this; + if (Array.isArray(route)) { + route.forEach(function (r) { + return _this.add(r); + }); + return undefined; + } + + var currentState = this.rootState; + var regex = '^'; + var types = { statics: 0, dynamics: 0, stars: 0 }; + var names = []; + var routeName = route.handler.name; + var isEmpty = true; var segments = parse(route.path, names, types); - for (var _iterator4 = segments, _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();;) { - var _ref4; - - if (_isArray4) { - if (_i4 >= _iterator4.length) break; - _ref4 = _iterator4[_i4++]; - } else { - _i4 = _iterator4.next(); - if (_i4.done) break; - _ref4 = _i4.value; - } - - var segment = _ref4; + for (var i = 0, ii = segments.length; i < ii; i++) { + var segment = segments[i]; if (segment instanceof EpsilonSegment) { continue; } @@ -291,18 +260,12 @@ var RouteRecognizer = (function () { }; RouteRecognizer.prototype.handlersFor = function handlersFor(name) { - var route = this.names[name], - result = []; - + var route = this.names[name]; if (!route) { throw new Error('There is no route named ' + name); } - for (var i = 0, l = route.handlers.length; i < l; i++) { - result.push(route.handlers[i]); - } - - return result; + return [].concat(route.handlers); }; RouteRecognizer.prototype.hasRoute = function hasRoute(name) { @@ -310,17 +273,16 @@ var RouteRecognizer = (function () { }; RouteRecognizer.prototype.generate = function generate(name, params) { - params = Object.assign({}, params); - - var route = this.names[name], - consumed = {}, - output = ''; + var routeParams = Object.assign({}, params); + var route = this.names[name]; if (!route) { throw new Error('There is no route named ' + name); } var segments = route.segments; + var consumed = {}; + var output = ''; for (var i = 0, l = segments.length; i < l; i++) { var segment = segments[i]; @@ -330,7 +292,7 @@ var RouteRecognizer = (function () { } output += '/'; - var segmentValue = segment.generate(params, consumed); + var segmentValue = segment.generate(routeParams, consumed); if (segmentValue === null || segmentValue === undefined) { throw new Error('A value is required for route parameter \'' + segment.name + '\' in route \'' + name + '\'.'); } @@ -343,131 +305,49 @@ var RouteRecognizer = (function () { } for (var param in consumed) { - delete params[param]; + delete routeParams[param]; } - output += this.generateQueryString(params); + var queryString = _aureliaPath.buildQueryString(routeParams); + output += queryString ? '?' + queryString : ''; return output; }; - RouteRecognizer.prototype.generateQueryString = function generateQueryString(params) { - var pairs = [], - keys = [], - encode = encodeURIComponent, - encodeKey = function encodeKey(k) { - return encode(k).replace('%24', '$'); - }; - - for (var key in params) { - if (params.hasOwnProperty(key)) { - keys.push(key); - } - } - - keys.sort(); - for (var i = 0, len = keys.length; i < len; i++) { - key = keys[i]; - var value = params[key]; - if (value === null || value === undefined) { - continue; - } - - if (Array.isArray(value)) { - var arrayKey = encodeKey(key) + '[]'; - for (var j = 0, l = value.length; j < l; j++) { - pairs.push(arrayKey + '=' + encode(value[j])); - } - } else { - pairs.push(encodeKey(key) + '=' + encode(value)); - } - } - - if (pairs.length === 0) { - return ''; - } - - return '?' + pairs.join('&'); - }; - - RouteRecognizer.prototype.parseQueryString = function parseQueryString(queryString) { + RouteRecognizer.prototype.recognize = function recognize(path) { + var states = [this.rootState]; var queryParams = {}; - if (!queryString || typeof queryString !== 'string') { - return queryParams; - } - - if (queryString.charAt(0) === '?') { - queryString = queryString.substr(1); - } + var isSlashDropped = false; + var normalizedPath = path; - var pairs = queryString.split('&'); - for (var i = 0; i < pairs.length; i++) { - var pair = pairs[i].split('='), - key = decodeURIComponent(pair[0]), - keyLength = key.length, - isArray = false, - value; - - if (!key) { - continue; - } else if (pair.length === 1) { - value = true; - } else { - if (keyLength > 2 && key.slice(keyLength - 2) === '[]') { - isArray = true; - key = key.slice(0, keyLength - 2); - if (!queryParams[key]) { - queryParams[key] = []; - } - } - value = pair[1] ? decodeURIComponent(pair[1]) : ''; - } - if (isArray) { - queryParams[key].push(value); - } else { - queryParams[key] = value; - } - } - return queryParams; - }; - - RouteRecognizer.prototype.recognize = function recognize(path) { - var states = [this.rootState], - pathLen, - i, - l, - queryStart, - queryParams = {}, - isSlashDropped = false; - - queryStart = path.indexOf('?'); + var queryStart = normalizedPath.indexOf('?'); if (queryStart !== -1) { - var queryString = path.substr(queryStart + 1, path.length); - path = path.substr(0, queryStart); - queryParams = this.parseQueryString(queryString); + var queryString = normalizedPath.substr(queryStart + 1, normalizedPath.length); + normalizedPath = normalizedPath.substr(0, queryStart); + queryParams = _aureliaPath.parseQueryString(queryString); } - path = decodeURI(path); + normalizedPath = decodeURI(normalizedPath); - if (path.charAt(0) !== '/') { - path = '/' + path; + if (normalizedPath.charAt(0) !== '/') { + normalizedPath = '/' + normalizedPath; } - pathLen = path.length; - if (pathLen > 1 && path.charAt(pathLen - 1) === '/') { - path = path.substr(0, pathLen - 1); + var pathLen = normalizedPath.length; + if (pathLen > 1 && normalizedPath.charAt(pathLen - 1) === '/') { + normalizedPath = normalizedPath.substr(0, pathLen - 1); isSlashDropped = true; } - for (i = 0, l = path.length; i < l; i++) { - states = recognizeChar(states, path.charAt(i)); + for (var i = 0, l = normalizedPath.length; i < l; i++) { + states = recognizeChar(states, normalizedPath.charAt(i)); if (!states.length) { break; } } var solutions = []; - for (i = 0, l = states.length; i < l; i++) { + for (var i = 0, l = states.length; i < l; i++) { if (states[i].handlers) { solutions.push(states[i]); } @@ -478,9 +358,10 @@ var RouteRecognizer = (function () { var state = solutions[0]; if (state && state.handlers) { if (isSlashDropped && state.regex.source.slice(-5) === '(.+)$') { - path = path + '/'; + normalizedPath = normalizedPath + '/'; } - return findHandler(state, path, queryParams); + + return findHandler(state, normalizedPath, queryParams); } }; @@ -500,33 +381,37 @@ var RecognizeResults = function RecognizeResults(queryParams) { }; function parse(route, names, types) { + var normalizedRoute = route; if (route.charAt(0) === '/') { - route = route.substr(1); + normalizedRoute = route.substr(1); } var results = []; - for (var _iterator5 = route.split('/'), _isArray5 = Array.isArray(_iterator5), _i5 = 0, _iterator5 = _isArray5 ? _iterator5 : _iterator5[Symbol.iterator]();;) { - var _ref5; + for (var _iterator3 = normalizedRoute.split('/'), _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) { + var _ref3; - if (_isArray5) { - if (_i5 >= _iterator5.length) break; - _ref5 = _iterator5[_i5++]; + if (_isArray3) { + if (_i3 >= _iterator3.length) break; + _ref3 = _iterator3[_i3++]; } else { - _i5 = _iterator5.next(); - if (_i5.done) break; - _ref5 = _i5.value; + _i3 = _iterator3.next(); + if (_i3.done) break; + _ref3 = _i3.value; } - var segment = _ref5; - - var match = undefined; + var segment = _ref3; - if (match = segment.match(/^:([^\/]+)$/)) { + var match = segment.match(/^:([^\/]+)$/); + if (match) { results.push(new DynamicSegment(match[1])); names.push(match[1]); types.dynamics++; - } else if (match = segment.match(/^\*([^\/]+)$/)) { + continue; + } + + match = segment.match(/^\*([^\/]+)$/); + if (match) { results.push(new StarSegment(match[1])); names.push(match[1]); types.stars++; @@ -573,39 +458,39 @@ function recognizeChar(states, ch) { for (var i = 0, l = states.length; i < l; i++) { var state = states[i]; - - nextStates = nextStates.concat(state.match(ch)); + nextStates.push.apply(nextStates, state.match(ch)); } return nextStates; } function findHandler(state, path, queryParams) { - var handlers = state.handlers, - regex = state.regex; - var captures = path.match(regex), - currentCapture = 1; + var handlers = state.handlers; + var regex = state.regex; + var captures = path.match(regex); + var currentCapture = 1; var result = new RecognizeResults(queryParams); for (var i = 0, l = handlers.length; i < l; i++) { - var handler = handlers[i], - names = handler.names, - params = {}; + var _handler = handlers[i]; + var _names = _handler.names; + var _params = {}; - for (var j = 0, m = names.length; j < m; j++) { - params[names[j]] = captures[currentCapture++]; + for (var j = 0, m = _names.length; j < m; j++) { + _params[_names[j]] = captures[currentCapture++]; } - result.push({ handler: handler.handler, params: params, isDynamic: !!names.length }); + result.push({ handler: _handler.handler, params: _params, isDynamic: !!_names.length }); } return result; } function addSegment(currentState, segment) { + var state = currentState; segment.eachChar(function (ch) { - currentState = currentState.put(ch); + state = state.put(ch); }); - return currentState; + return state; } \ No newline at end of file diff --git a/dist/es6/aurelia-route-recognizer.d.ts b/dist/es6/aurelia-route-recognizer.d.ts index ce4bf91..ef4a9ca 100644 --- a/dist/es6/aurelia-route-recognizer.d.ts +++ b/dist/es6/aurelia-route-recognizer.d.ts @@ -1,5 +1,6 @@ declare module 'aurelia-route-recognizer' { - import * as core from 'core-js'; + import 'core-js'; + import { buildQueryString, parseQueryString } from 'aurelia-path'; export interface RouteHandler { name: string; } @@ -67,7 +68,7 @@ declare module 'aurelia-route-recognizer' { constructor(string: string); eachChar(callback: ((spec: CharSpec) => void)): void; regex(): string; - generate(params: Object, consumed: Object): string; + generate(): string; } export class DynamicSegment { constructor(name: string); @@ -82,84 +83,61 @@ declare module 'aurelia-route-recognizer' { generate(params: Object, consumed: Object): string; } export class EpsilonSegment { - eachChar(callback: ((spec: CharSpec) => void)): void; + eachChar(): void; regex(): string; - generate(params: Object, consumed: Object): string; + generate(): string; } /** - * Class that parses route patterns and matches path strings. - * - * @class RouteRecognizer - * @constructor - */ + * Class that parses route patterns and matches path strings. + * + * @class RouteRecognizer + * @constructor + */ export class RouteRecognizer { constructor(); /** - * Parse a route pattern and add it to the collection of recognized routes. - * - * @method add - * @param {Object} route The route to add. - */ + * Parse a route pattern and add it to the collection of recognized routes. + * + * @param route The route to add. + */ add(route: ConfigurableRoute | ConfigurableRoute[]): State; /** - * Retrieve the handlers registered for the named route. - * - * @method handlersFor - * @param {String} name The name of the route. - * @return {Array} The handlers. - */ + * Retrieve the handlers registered for the named route. + * + * @param name The name of the route. + * @returns The handlers. + */ handlersFor(name: string): HandlerEntry[]; /** - * Check if this RouteRecognizer recognizes a named route. - * - * @method hasRoute - * @param {String} name The name of the route. - * @return {Boolean} True if the named route is recognized. - */ + * Check if this RouteRecognizer recognizes a named route. + * + * @param name The name of the route. + * @returns True if the named route is recognized. + */ hasRoute(name: string): boolean; /** - * Generate a path and query string from a route name and params object. - * - * @method generate - * @param {String} name The name of the route. - * @param {Object} params The route params to use when populating the pattern. - * Properties not required by the pattern will be appended to the query string. - * @return {String} The generated absolute path and query string. - */ + * Generate a path and query string from a route name and params object. + * + * @param name The name of the route. + * @param params The route params to use when populating the pattern. + * Properties not required by the pattern will be appended to the query string. + * @returns The generated absolute path and query string. + */ generate(name: string, params: Object): string; /** - * Generate a query string from an object. - * - * @method generateQueryString - * @param {Object} params Object containing the keys and values to be used. - * @return {String} The generated query string, including leading '?'. - */ - generateQueryString(params: Object): string; - - /** - * Parse a query string. - * - * @method parseQueryString - * @param {String} The query string to parse. - * @return {Object} Object with keys and values mapped from the query string. - */ - parseQueryString(queryString: string): Object; - - /** - * Match a path string against registered route patterns. - * - * @method recognize - * @param {String} path The path to attempt to match. - * @return {Array} Array of objects containing `handler`, `params`, and - * `isDynanic` values for the matched route(s), or undefined if no match - * was found. - */ + * Match a path string against registered route patterns. + * + * @param path The path to attempt to match. + * @returns Array of objects containing `handler`, `params`, and + * `isDynanic` values for the matched route(s), or undefined if no match + * was found. + */ recognize(path: string): RecognizedRoute[]; } class RecognizeResults { diff --git a/dist/es6/aurelia-route-recognizer.js b/dist/es6/aurelia-route-recognizer.js index b8937e2..a35f16c 100644 --- a/dist/es6/aurelia-route-recognizer.js +++ b/dist/es6/aurelia-route-recognizer.js @@ -1,4 +1,5 @@ -import * as core from 'core-js'; +import 'core-js'; +import {buildQueryString,parseQueryString} from 'aurelia-path'; // A State has a character specification and (`charSpec`) and a list of possible // subsequent states (`nextStates`). @@ -25,8 +26,8 @@ export class State { get(charSpec: CharSpec): State { for (let child of this.nextStates) { - var isEqual = child.charSpec.validChars === charSpec.validChars && - child.charSpec.invalidChars === charSpec.invalidChars; + let isEqual = child.charSpec.validChars === charSpec.validChars + && child.charSpec.invalidChars === charSpec.invalidChars; if (isEqual) { return child; @@ -35,7 +36,7 @@ export class State { } put(charSpec: CharSpec): State { - var state = this.get(charSpec); + let state = this.get(charSpec); // If the character specification already exists in a child of the current // state, just return that state. @@ -62,20 +63,19 @@ export class State { // Find a list of child states matching the next character match(ch: string): State[] { - var nextStates = this.nextStates, results = [], - child, charSpec, chars; + let nextStates = this.nextStates; + let results = []; - for (var i = 0, l = nextStates.length; i < l; i++) { - child = nextStates[i]; + for (let i = 0, l = nextStates.length; i < l; i++) { + let child = nextStates[i]; + let charSpec = child.charSpec; - charSpec = child.charSpec; - - if (typeof (chars = charSpec.validChars) !== 'undefined') { - if (chars.indexOf(ch) !== -1) { + if (charSpec.validChars !== undefined) { + if (charSpec.validChars.indexOf(ch) !== -1) { results.push(child); } - } else if (typeof (chars = charSpec.invalidChars) !== 'undefined') { - if (chars.indexOf(ch) === -1) { + } else if (charSpec.invalidChars !== undefined) { + if (charSpec.invalidChars.indexOf(ch) === -1) { results.push(child); } } @@ -83,7 +83,7 @@ export class State { return results; } -}; +} const specials = [ '/', '.', '*', '+', '?', '|', @@ -110,11 +110,11 @@ const escapeRegex = new RegExp('(\\' + specials.join('|\\') + ')', 'g'); // * `repeat`: true if the character specification can repeat export class StaticSegment { - constructor(string:string) { + constructor(string: string) { this.string = string; } - eachChar(callback: (spec:CharSpec) => void): void { + eachChar(callback: (spec: CharSpec) => void): void { for (let ch of this.string) { callback({ validChars: ch }); } @@ -124,7 +124,7 @@ export class StaticSegment { return this.string.replace(escapeRegex, '\\$1'); } - generate(params:Object, consumed:Object): string { + generate(): string { return this.string; } } @@ -134,7 +134,7 @@ export class DynamicSegment { this.name = name; } - eachChar(callback:(spec :CharSpec) => void): void { + eachChar(callback: (spec: CharSpec) => void): void { callback({ invalidChars: '/', repeat: true }); } @@ -153,7 +153,7 @@ export class StarSegment { this.name = name; } - eachChar(callback: (spec:CharSpec) => void): void { + eachChar(callback: (spec: CharSpec) => void): void { callback({ invalidChars: '', repeat: true }); } @@ -168,9 +168,16 @@ export class StarSegment { } export class EpsilonSegment { - eachChar(callback: (spec:CharSpec) => void): void {} - regex(): string { return ''; } - generate(params: Object, consumed: Object): string { return ''; } + eachChar(): void { + } + + regex(): string { + return ''; + } + + generate(): string { + return ''; + } } interface RouteHandler { @@ -200,11 +207,11 @@ interface CharSpec { } /** - * Class that parses route patterns and matches path strings. - * - * @class RouteRecognizer - * @constructor - */ +* Class that parses route patterns and matches path strings. +* +* @class RouteRecognizer +* @constructor +*/ export class RouteRecognizer { constructor() { this.rootState = new State(); @@ -212,27 +219,26 @@ export class RouteRecognizer { } /** - * Parse a route pattern and add it to the collection of recognized routes. - * - * @method add - * @param {Object} route The route to add. - */ + * Parse a route pattern and add it to the collection of recognized routes. + * + * @param route The route to add. + */ add(route: ConfigurableRoute|ConfigurableRoute[]): State { if (Array.isArray(route)) { - for (let r of route) { - this.add(r); - } - - return; + route.forEach(r => this.add(r)); + return undefined; } - var currentState = this.rootState, regex = '^', - types = { statics: 0, dynamics: 0, stars: 0 }, - names = [], routeName = route.handler.name, - isEmpty = true; + let currentState = this.rootState; + let regex = '^'; + let types = { statics: 0, dynamics: 0, stars: 0 }; + let names = []; + let routeName = route.handler.name; + let isEmpty = true; + let segments = parse(route.path, names, types); - var segments = parse(route.path, names, types); - for (let segment of segments) { + for (let i = 0, ii = segments.length; i < ii; i++) { + let segment = segments[i]; if (segment instanceof EpsilonSegment) { continue; } @@ -253,7 +259,7 @@ export class RouteRecognizer { regex += '/'; } - var handlers = [{ handler: route.handler, names: names }]; + let handlers = [{ handler: route.handler, names: names }]; if (routeName) { this.names[routeName] = { @@ -270,68 +276,59 @@ export class RouteRecognizer { } /** - * Retrieve the handlers registered for the named route. - * - * @method handlersFor - * @param {String} name The name of the route. - * @return {Array} The handlers. - */ + * Retrieve the handlers registered for the named route. + * + * @param name The name of the route. + * @returns The handlers. + */ handlersFor(name: string): HandlerEntry[] { - var route = this.names[name], - result = []; - + let route = this.names[name]; if (!route) { throw new Error(`There is no route named ${name}`); } - for (var i=0, l=route.handlers.length; i encode(k).replace('%24', '$'); - - for (var key in params) { - if (params.hasOwnProperty(key)) { - keys.push(key); - } - } - - keys.sort(); - for (var i = 0, len = keys.length; i < len; i++) { - key = keys[i]; - var value = params[key]; - if (value === null || value === undefined) { - continue; - } - - if (Array.isArray(value)) { - var arrayKey = `${encodeKey(key)}[]`; - for (var j = 0, l = value.length; j < l; j++) { - pairs.push(`${arrayKey}=${encode(value[j])}`); - } - } else { - pairs.push(`${encodeKey(key)}=${encode(value)}`); - } - } - - if (pairs.length === 0) { - return ''; - } - - return '?' + pairs.join('&'); - } - - /** - * Parse a query string. - * - * @method parseQueryString - * @param {String} The query string to parse. - * @return {Object} Object with keys and values mapped from the query string. - */ - parseQueryString(queryString: string): Object { - var queryParams = {}; - if (!queryString || typeof queryString !== 'string') { - return queryParams; - } - - if (queryString.charAt(0) === '?') { - queryString = queryString.substr(1); - } - - var pairs = queryString.split('&'); - for(var i = 0; i < pairs.length; i++) { - var pair = pairs[i].split('='), - key = decodeURIComponent(pair[0]), - keyLength = key.length, - isArray = false, - value; - - if (!key) { - continue; - } else if (pair.length === 1) { - value = true; - } else { - //Handle arrays - if (keyLength > 2 && key.slice(keyLength -2) === '[]') { - isArray = true; - key = key.slice(0, keyLength - 2); - if(!queryParams[key]) { - queryParams[key] = []; - } - } - value = pair[1] ? decodeURIComponent(pair[1]) : ''; - } - if (isArray) { - queryParams[key].push(value); - } else { - queryParams[key] = value; - } - } - return queryParams; - } - - /** - * Match a path string against registered route patterns. - * - * @method recognize - * @param {String} path The path to attempt to match. - * @return {Array} Array of objects containing `handler`, `params`, and - * `isDynanic` values for the matched route(s), or undefined if no match - * was found. - */ + * Match a path string against registered route patterns. + * + * @param path The path to attempt to match. + * @returns Array of objects containing `handler`, `params`, and + * `isDynanic` values for the matched route(s), or undefined if no match + * was found. + */ recognize(path: string): RecognizedRoute[] { - var states = [ this.rootState ], - pathLen, i, l, queryStart, queryParams = {}, - isSlashDropped = false; + let states = [this.rootState]; + let queryParams = {}; + let isSlashDropped = false; + let normalizedPath = path; - queryStart = path.indexOf('?'); + let queryStart = normalizedPath.indexOf('?'); if (queryStart !== -1) { - var queryString = path.substr(queryStart + 1, path.length); - path = path.substr(0, queryStart); - queryParams = this.parseQueryString(queryString); + let queryString = normalizedPath.substr(queryStart + 1, normalizedPath.length); + normalizedPath = normalizedPath.substr(0, queryStart); + queryParams = parseQueryString(queryString); } - path = decodeURI(path); + normalizedPath = decodeURI(normalizedPath); - if (path.charAt(0) !== '/') { - path = '/' + path; + if (normalizedPath.charAt(0) !== '/') { + normalizedPath = '/' + normalizedPath; } - pathLen = path.length; - if (pathLen > 1 && path.charAt(pathLen - 1) === '/') { - path = path.substr(0, pathLen - 1); + let pathLen = normalizedPath.length; + if (pathLen > 1 && normalizedPath.charAt(pathLen - 1) === '/') { + normalizedPath = normalizedPath.substr(0, pathLen - 1); isSlashDropped = true; } - for (i = 0, l = path.length; i < l; i++) { - states = recognizeChar(states, path.charAt(i)); + for (let i = 0, l = normalizedPath.length; i < l; i++) { + states = recognizeChar(states, normalizedPath.charAt(i)); if (!states.length) { break; } } - var solutions = []; - for (i=0, l=states.length; i { - currentState = currentState.put(ch); + state = state.put(ch); }); - return currentState; + return state; } diff --git a/dist/system/aurelia-route-recognizer.d.ts b/dist/system/aurelia-route-recognizer.d.ts index ce4bf91..ef4a9ca 100644 --- a/dist/system/aurelia-route-recognizer.d.ts +++ b/dist/system/aurelia-route-recognizer.d.ts @@ -1,5 +1,6 @@ declare module 'aurelia-route-recognizer' { - import * as core from 'core-js'; + import 'core-js'; + import { buildQueryString, parseQueryString } from 'aurelia-path'; export interface RouteHandler { name: string; } @@ -67,7 +68,7 @@ declare module 'aurelia-route-recognizer' { constructor(string: string); eachChar(callback: ((spec: CharSpec) => void)): void; regex(): string; - generate(params: Object, consumed: Object): string; + generate(): string; } export class DynamicSegment { constructor(name: string); @@ -82,84 +83,61 @@ declare module 'aurelia-route-recognizer' { generate(params: Object, consumed: Object): string; } export class EpsilonSegment { - eachChar(callback: ((spec: CharSpec) => void)): void; + eachChar(): void; regex(): string; - generate(params: Object, consumed: Object): string; + generate(): string; } /** - * Class that parses route patterns and matches path strings. - * - * @class RouteRecognizer - * @constructor - */ + * Class that parses route patterns and matches path strings. + * + * @class RouteRecognizer + * @constructor + */ export class RouteRecognizer { constructor(); /** - * Parse a route pattern and add it to the collection of recognized routes. - * - * @method add - * @param {Object} route The route to add. - */ + * Parse a route pattern and add it to the collection of recognized routes. + * + * @param route The route to add. + */ add(route: ConfigurableRoute | ConfigurableRoute[]): State; /** - * Retrieve the handlers registered for the named route. - * - * @method handlersFor - * @param {String} name The name of the route. - * @return {Array} The handlers. - */ + * Retrieve the handlers registered for the named route. + * + * @param name The name of the route. + * @returns The handlers. + */ handlersFor(name: string): HandlerEntry[]; /** - * Check if this RouteRecognizer recognizes a named route. - * - * @method hasRoute - * @param {String} name The name of the route. - * @return {Boolean} True if the named route is recognized. - */ + * Check if this RouteRecognizer recognizes a named route. + * + * @param name The name of the route. + * @returns True if the named route is recognized. + */ hasRoute(name: string): boolean; /** - * Generate a path and query string from a route name and params object. - * - * @method generate - * @param {String} name The name of the route. - * @param {Object} params The route params to use when populating the pattern. - * Properties not required by the pattern will be appended to the query string. - * @return {String} The generated absolute path and query string. - */ + * Generate a path and query string from a route name and params object. + * + * @param name The name of the route. + * @param params The route params to use when populating the pattern. + * Properties not required by the pattern will be appended to the query string. + * @returns The generated absolute path and query string. + */ generate(name: string, params: Object): string; /** - * Generate a query string from an object. - * - * @method generateQueryString - * @param {Object} params Object containing the keys and values to be used. - * @return {String} The generated query string, including leading '?'. - */ - generateQueryString(params: Object): string; - - /** - * Parse a query string. - * - * @method parseQueryString - * @param {String} The query string to parse. - * @return {Object} Object with keys and values mapped from the query string. - */ - parseQueryString(queryString: string): Object; - - /** - * Match a path string against registered route patterns. - * - * @method recognize - * @param {String} path The path to attempt to match. - * @return {Array} Array of objects containing `handler`, `params`, and - * `isDynanic` values for the matched route(s), or undefined if no match - * was found. - */ + * Match a path string against registered route patterns. + * + * @param path The path to attempt to match. + * @returns Array of objects containing `handler`, `params`, and + * `isDynanic` values for the matched route(s), or undefined if no match + * was found. + */ recognize(path: string): RecognizedRoute[]; } class RecognizeResults { diff --git a/dist/system/aurelia-route-recognizer.js b/dist/system/aurelia-route-recognizer.js index 3f29165..05309fa 100644 --- a/dist/system/aurelia-route-recognizer.js +++ b/dist/system/aurelia-route-recognizer.js @@ -1,38 +1,42 @@ -System.register(['core-js'], function (_export) { +System.register(['core-js', 'aurelia-path'], function (_export) { 'use strict'; - var core, State, specials, escapeRegex, StaticSegment, DynamicSegment, StarSegment, EpsilonSegment, RouteRecognizer, RecognizeResults; + var buildQueryString, parseQueryString, State, specials, escapeRegex, StaticSegment, DynamicSegment, StarSegment, EpsilonSegment, RouteRecognizer, RecognizeResults; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } function parse(route, names, types) { + var normalizedRoute = route; if (route.charAt(0) === '/') { - route = route.substr(1); + normalizedRoute = route.substr(1); } var results = []; - for (var _iterator5 = route.split('/'), _isArray5 = Array.isArray(_iterator5), _i5 = 0, _iterator5 = _isArray5 ? _iterator5 : _iterator5[Symbol.iterator]();;) { - var _ref5; + for (var _iterator3 = normalizedRoute.split('/'), _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) { + var _ref3; - if (_isArray5) { - if (_i5 >= _iterator5.length) break; - _ref5 = _iterator5[_i5++]; + if (_isArray3) { + if (_i3 >= _iterator3.length) break; + _ref3 = _iterator3[_i3++]; } else { - _i5 = _iterator5.next(); - if (_i5.done) break; - _ref5 = _i5.value; + _i3 = _iterator3.next(); + if (_i3.done) break; + _ref3 = _i3.value; } - var segment = _ref5; + var segment = _ref3; - var match = undefined; - - if (match = segment.match(/^:([^\/]+)$/)) { + var match = segment.match(/^:([^\/]+)$/); + if (match) { results.push(new DynamicSegment(match[1])); names.push(match[1]); types.dynamics++; - } else if (match = segment.match(/^\*([^\/]+)$/)) { + continue; + } + + match = segment.match(/^\*([^\/]+)$/); + if (match) { results.push(new StarSegment(match[1])); names.push(match[1]); types.stars++; @@ -79,45 +83,46 @@ System.register(['core-js'], function (_export) { for (var i = 0, l = states.length; i < l; i++) { var state = states[i]; - - nextStates = nextStates.concat(state.match(ch)); + nextStates.push.apply(nextStates, state.match(ch)); } return nextStates; } function findHandler(state, path, queryParams) { - var handlers = state.handlers, - regex = state.regex; - var captures = path.match(regex), - currentCapture = 1; + var handlers = state.handlers; + var regex = state.regex; + var captures = path.match(regex); + var currentCapture = 1; var result = new RecognizeResults(queryParams); for (var i = 0, l = handlers.length; i < l; i++) { - var handler = handlers[i], - names = handler.names, - params = {}; + var _handler = handlers[i]; + var _names = _handler.names; + var _params = {}; - for (var j = 0, m = names.length; j < m; j++) { - params[names[j]] = captures[currentCapture++]; + for (var j = 0, m = _names.length; j < m; j++) { + _params[_names[j]] = captures[currentCapture++]; } - result.push({ handler: handler.handler, params: params, isDynamic: !!names.length }); + result.push({ handler: _handler.handler, params: _params, isDynamic: !!_names.length }); } return result; } function addSegment(currentState, segment) { + var state = currentState; segment.eachChar(function (ch) { - currentState = currentState.put(ch); + state = state.put(ch); }); - return currentState; + return state; } return { - setters: [function (_coreJs) { - core = _coreJs; + setters: [function (_coreJs) {}, function (_aureliaPath) { + buildQueryString = _aureliaPath.buildQueryString; + parseQueryString = _aureliaPath.parseQueryString; }], execute: function () { State = (function () { @@ -170,23 +175,19 @@ System.register(['core-js'], function (_export) { }; State.prototype.match = function match(ch) { - var nextStates = this.nextStates, - results = [], - child, - charSpec, - chars; + var nextStates = this.nextStates; + var results = []; for (var i = 0, l = nextStates.length; i < l; i++) { - child = nextStates[i]; + var child = nextStates[i]; + var charSpec = child.charSpec; - charSpec = child.charSpec; - - if (typeof (chars = charSpec.validChars) !== 'undefined') { - if (chars.indexOf(ch) !== -1) { + if (charSpec.validChars !== undefined) { + if (charSpec.validChars.indexOf(ch) !== -1) { results.push(child); } - } else if (typeof (chars = charSpec.invalidChars) !== 'undefined') { - if (chars.indexOf(ch) === -1) { + } else if (charSpec.invalidChars !== undefined) { + if (charSpec.invalidChars.indexOf(ch) === -1) { results.push(child); } } @@ -200,8 +201,6 @@ System.register(['core-js'], function (_export) { _export('State', State); - ; - specials = ['/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\']; escapeRegex = new RegExp('(\\' + specials.join('|\\') + ')', 'g'); @@ -235,7 +234,7 @@ System.register(['core-js'], function (_export) { return this.string.replace(escapeRegex, '\\$1'); }; - StaticSegment.prototype.generate = function generate(params, consumed) { + StaticSegment.prototype.generate = function generate() { return this.string; }; @@ -299,13 +298,13 @@ System.register(['core-js'], function (_export) { _classCallCheck(this, EpsilonSegment); } - EpsilonSegment.prototype.eachChar = function eachChar(callback) {}; + EpsilonSegment.prototype.eachChar = function eachChar() {}; EpsilonSegment.prototype.regex = function regex() { return ''; }; - EpsilonSegment.prototype.generate = function generate(params, consumed) { + EpsilonSegment.prototype.generate = function generate() { return ''; }; @@ -323,49 +322,25 @@ System.register(['core-js'], function (_export) { } RouteRecognizer.prototype.add = function add(route) { - if (Array.isArray(route)) { - for (var _iterator3 = route, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) { - var _ref3; - - if (_isArray3) { - if (_i3 >= _iterator3.length) break; - _ref3 = _iterator3[_i3++]; - } else { - _i3 = _iterator3.next(); - if (_i3.done) break; - _ref3 = _i3.value; - } - - var r = _ref3; - - this.add(r); - } + var _this = this; - return; + if (Array.isArray(route)) { + route.forEach(function (r) { + return _this.add(r); + }); + return undefined; } - var currentState = this.rootState, - regex = '^', - types = { statics: 0, dynamics: 0, stars: 0 }, - names = [], - routeName = route.handler.name, - isEmpty = true; - + var currentState = this.rootState; + var regex = '^'; + var types = { statics: 0, dynamics: 0, stars: 0 }; + var names = []; + var routeName = route.handler.name; + var isEmpty = true; var segments = parse(route.path, names, types); - for (var _iterator4 = segments, _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();;) { - var _ref4; - - if (_isArray4) { - if (_i4 >= _iterator4.length) break; - _ref4 = _iterator4[_i4++]; - } else { - _i4 = _iterator4.next(); - if (_i4.done) break; - _ref4 = _i4.value; - } - - var segment = _ref4; + for (var i = 0, ii = segments.length; i < ii; i++) { + var segment = segments[i]; if (segment instanceof EpsilonSegment) { continue; } @@ -401,18 +376,12 @@ System.register(['core-js'], function (_export) { }; RouteRecognizer.prototype.handlersFor = function handlersFor(name) { - var route = this.names[name], - result = []; - + var route = this.names[name]; if (!route) { throw new Error('There is no route named ' + name); } - for (var i = 0, l = route.handlers.length; i < l; i++) { - result.push(route.handlers[i]); - } - - return result; + return [].concat(route.handlers); }; RouteRecognizer.prototype.hasRoute = function hasRoute(name) { @@ -420,17 +389,16 @@ System.register(['core-js'], function (_export) { }; RouteRecognizer.prototype.generate = function generate(name, params) { - params = Object.assign({}, params); - - var route = this.names[name], - consumed = {}, - output = ''; + var routeParams = Object.assign({}, params); + var route = this.names[name]; if (!route) { throw new Error('There is no route named ' + name); } var segments = route.segments; + var consumed = {}; + var output = ''; for (var i = 0, l = segments.length; i < l; i++) { var segment = segments[i]; @@ -440,7 +408,7 @@ System.register(['core-js'], function (_export) { } output += '/'; - var segmentValue = segment.generate(params, consumed); + var segmentValue = segment.generate(routeParams, consumed); if (segmentValue === null || segmentValue === undefined) { throw new Error('A value is required for route parameter \'' + segment.name + '\' in route \'' + name + '\'.'); } @@ -453,131 +421,49 @@ System.register(['core-js'], function (_export) { } for (var param in consumed) { - delete params[param]; + delete routeParams[param]; } - output += this.generateQueryString(params); + var queryString = buildQueryString(routeParams); + output += queryString ? '?' + queryString : ''; return output; }; - RouteRecognizer.prototype.generateQueryString = function generateQueryString(params) { - var pairs = [], - keys = [], - encode = encodeURIComponent, - encodeKey = function encodeKey(k) { - return encode(k).replace('%24', '$'); - }; - - for (var key in params) { - if (params.hasOwnProperty(key)) { - keys.push(key); - } - } - - keys.sort(); - for (var i = 0, len = keys.length; i < len; i++) { - key = keys[i]; - var value = params[key]; - if (value === null || value === undefined) { - continue; - } - - if (Array.isArray(value)) { - var arrayKey = encodeKey(key) + '[]'; - for (var j = 0, l = value.length; j < l; j++) { - pairs.push(arrayKey + '=' + encode(value[j])); - } - } else { - pairs.push(encodeKey(key) + '=' + encode(value)); - } - } - - if (pairs.length === 0) { - return ''; - } - - return '?' + pairs.join('&'); - }; - - RouteRecognizer.prototype.parseQueryString = function parseQueryString(queryString) { + RouteRecognizer.prototype.recognize = function recognize(path) { + var states = [this.rootState]; var queryParams = {}; - if (!queryString || typeof queryString !== 'string') { - return queryParams; - } - - if (queryString.charAt(0) === '?') { - queryString = queryString.substr(1); - } - - var pairs = queryString.split('&'); - for (var i = 0; i < pairs.length; i++) { - var pair = pairs[i].split('='), - key = decodeURIComponent(pair[0]), - keyLength = key.length, - isArray = false, - value; + var isSlashDropped = false; + var normalizedPath = path; - if (!key) { - continue; - } else if (pair.length === 1) { - value = true; - } else { - if (keyLength > 2 && key.slice(keyLength - 2) === '[]') { - isArray = true; - key = key.slice(0, keyLength - 2); - if (!queryParams[key]) { - queryParams[key] = []; - } - } - value = pair[1] ? decodeURIComponent(pair[1]) : ''; - } - if (isArray) { - queryParams[key].push(value); - } else { - queryParams[key] = value; - } - } - return queryParams; - }; - - RouteRecognizer.prototype.recognize = function recognize(path) { - var states = [this.rootState], - pathLen, - i, - l, - queryStart, - queryParams = {}, - isSlashDropped = false; - - queryStart = path.indexOf('?'); + var queryStart = normalizedPath.indexOf('?'); if (queryStart !== -1) { - var queryString = path.substr(queryStart + 1, path.length); - path = path.substr(0, queryStart); - queryParams = this.parseQueryString(queryString); + var queryString = normalizedPath.substr(queryStart + 1, normalizedPath.length); + normalizedPath = normalizedPath.substr(0, queryStart); + queryParams = parseQueryString(queryString); } - path = decodeURI(path); + normalizedPath = decodeURI(normalizedPath); - if (path.charAt(0) !== '/') { - path = '/' + path; + if (normalizedPath.charAt(0) !== '/') { + normalizedPath = '/' + normalizedPath; } - pathLen = path.length; - if (pathLen > 1 && path.charAt(pathLen - 1) === '/') { - path = path.substr(0, pathLen - 1); + var pathLen = normalizedPath.length; + if (pathLen > 1 && normalizedPath.charAt(pathLen - 1) === '/') { + normalizedPath = normalizedPath.substr(0, pathLen - 1); isSlashDropped = true; } - for (i = 0, l = path.length; i < l; i++) { - states = recognizeChar(states, path.charAt(i)); + for (var i = 0, l = normalizedPath.length; i < l; i++) { + states = recognizeChar(states, normalizedPath.charAt(i)); if (!states.length) { break; } } var solutions = []; - for (i = 0, l = states.length; i < l; i++) { + for (var i = 0, l = states.length; i < l; i++) { if (states[i].handlers) { solutions.push(states[i]); } @@ -588,9 +474,10 @@ System.register(['core-js'], function (_export) { var state = solutions[0]; if (state && state.handlers) { if (isSlashDropped && state.regex.source.slice(-5) === '(.+)$') { - path = path + '/'; + normalizedPath = normalizedPath + '/'; } - return findHandler(state, path, queryParams); + + return findHandler(state, normalizedPath, queryParams); } }; diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index 069af5f..674ea6e 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -1,3 +1,17 @@ +## 0.7.0 (2015-09-04) + + +#### Bug Fixes + +* **build:** update linting, testing and tools ([f49bf0d3](http://github.com/aurelia/route-recognizer/commit/f49bf0d3db3bb453807b60f4eb1c673dec945a16)) + + +#### Features + +* **docs:** generate api.json from .d.ts file ([e5441c97](http://github.com/aurelia/route-recognizer/commit/e5441c970d741edd42322c70a3abb2d514c69fa4)) +* **route-recognizer:** use query string helpers from aurelia-path ([a96f5a0f](http://github.com/aurelia/route-recognizer/commit/a96f5a0f01cf64182ec09da1d064b67245ae59bf)) + + ### 0.6.2 (2015-08-14) diff --git a/package.json b/package.json index f1b23c7..dea7e9d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "aurelia-route-recognizer", - "version": "0.6.2", + "version": "0.7.0", "description": "A lightweight JavaScript library that matches paths against registered routes. It includes support for dynamic and star segments and nested handlers.", "keywords": [ "aurelia", @@ -24,7 +24,7 @@ "lib": "dist/amd" }, "dependencies": { - "aurelia-path": "github:aurelia/path@^0.8.1", + "aurelia-path": "github:aurelia/path@^0.9.0", "core-js": "npm:core-js@^0.9.5" }, "devDependencies": {