UNPKG

aurelia-bootstrap

Version:
476 lines (360 loc) 12.4 kB
/* */ define(['exports', 'aurelia-path'], function (exports, _aureliaPath) { 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.RouteRecognizer = exports.EpsilonSegment = exports.StarSegment = exports.DynamicSegment = exports.StaticSegment = exports.State = undefined; var State = exports.State = function () { function State(charSpec) { this.charSpec = charSpec; this.nextStates = []; } State.prototype.get = function get(charSpec) { for (var _iterator = this.nextStates, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { var _ref; if (_isArray) { if (_i >= _iterator.length) break; _ref = _iterator[_i++]; } else { _i = _iterator.next(); if (_i.done) break; _ref = _i.value; } var child = _ref; var isEqual = child.charSpec.validChars === charSpec.validChars && child.charSpec.invalidChars === charSpec.invalidChars; if (isEqual) { return child; } } return undefined; }; State.prototype.put = function put(charSpec) { var state = this.get(charSpec); if (state) { return state; } state = new State(charSpec); this.nextStates.push(state); if (charSpec.repeat) { state.nextStates.push(state); } return state; }; State.prototype.match = function match(ch) { var nextStates = this.nextStates; var results = []; for (var i = 0, l = nextStates.length; i < l; i++) { var child = nextStates[i]; var charSpec = child.charSpec; if (charSpec.validChars !== undefined) { if (charSpec.validChars.indexOf(ch) !== -1) { results.push(child); } } else if (charSpec.invalidChars !== undefined) { if (charSpec.invalidChars.indexOf(ch) === -1) { results.push(child); } } } return results; }; return State; }(); var specials = ['/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\']; var escapeRegex = new RegExp('(\\' + specials.join('|\\') + ')', 'g'); var StaticSegment = exports.StaticSegment = function () { function StaticSegment(string, caseSensitive) { this.string = string; this.caseSensitive = caseSensitive; } StaticSegment.prototype.eachChar = function eachChar(callback) { var s = this.string; for (var i = 0, ii = s.length; i < ii; ++i) { var ch = s[i]; callback({ validChars: this.caseSensitive ? ch : ch.toUpperCase() + ch.toLowerCase() }); } }; StaticSegment.prototype.regex = function regex() { return this.string.replace(escapeRegex, '\\$1'); }; StaticSegment.prototype.generate = function generate() { return this.string; }; return StaticSegment; }(); var DynamicSegment = exports.DynamicSegment = function () { function DynamicSegment(name) { this.name = name; } DynamicSegment.prototype.eachChar = function eachChar(callback) { callback({ invalidChars: '/', repeat: true }); }; DynamicSegment.prototype.regex = function regex() { return '([^/]+)'; }; DynamicSegment.prototype.generate = function generate(params, consumed) { consumed[this.name] = true; return params[this.name]; }; return DynamicSegment; }(); var StarSegment = exports.StarSegment = function () { function StarSegment(name) { this.name = name; } StarSegment.prototype.eachChar = function eachChar(callback) { callback({ invalidChars: '', repeat: true }); }; StarSegment.prototype.regex = function regex() { return '(.+)'; }; StarSegment.prototype.generate = function generate(params, consumed) { consumed[this.name] = true; return params[this.name]; }; return StarSegment; }(); var EpsilonSegment = exports.EpsilonSegment = function () { function EpsilonSegment() { } EpsilonSegment.prototype.eachChar = function eachChar() {}; EpsilonSegment.prototype.regex = function regex() { return ''; }; EpsilonSegment.prototype.generate = function generate() { return ''; }; return EpsilonSegment; }(); var RouteRecognizer = exports.RouteRecognizer = function () { function RouteRecognizer() { this.rootState = new State(); this.names = {}; } RouteRecognizer.prototype.add = function add(route) { 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, route.caseSensitive); for (var i = 0, ii = segments.length; i < ii; i++) { var segment = segments[i]; if (segment instanceof EpsilonSegment) { continue; } isEmpty = false; currentState = currentState.put({ validChars: '/' }); regex += '/'; currentState = addSegment(currentState, segment); regex += segment.regex(); } if (isEmpty) { currentState = currentState.put({ validChars: '/' }); regex += '/'; } var handlers = [{ handler: route.handler, names: names }]; if (routeName) { var routeNames = Array.isArray(routeName) ? routeName : [routeName]; for (var _i2 = 0; _i2 < routeNames.length; _i2++) { this.names[routeNames[_i2]] = { segments: segments, handlers: handlers }; } } currentState.handlers = handlers; currentState.regex = new RegExp(regex + '$', route.caseSensitive ? '' : 'i'); currentState.types = types; return currentState; }; RouteRecognizer.prototype.handlersFor = function handlersFor(name) { var route = this.names[name]; if (!route) { throw new Error('There is no route named ' + name); } return [].concat(route.handlers); }; RouteRecognizer.prototype.hasRoute = function hasRoute(name) { return !!this.names[name]; }; RouteRecognizer.prototype.generate = function generate(name, params) { var route = this.names[name]; if (!route) { throw new Error('There is no route named ' + name); } var handler = route.handlers[0].handler; if (handler.generationUsesHref) { return handler.href; } var routeParams = Object.assign({}, params); var segments = route.segments; var consumed = {}; var output = ''; for (var i = 0, l = segments.length; i < l; i++) { var segment = segments[i]; if (segment instanceof EpsilonSegment) { continue; } output += '/'; 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 + '\'.'); } output += segmentValue; } if (output.charAt(0) !== '/') { output = '/' + output; } for (var param in consumed) { delete routeParams[param]; } var queryString = (0, _aureliaPath.buildQueryString)(routeParams); output += queryString ? '?' + queryString : ''; return output; }; RouteRecognizer.prototype.recognize = function recognize(path) { var states = [this.rootState]; var queryParams = {}; var isSlashDropped = false; var normalizedPath = path; var queryStart = normalizedPath.indexOf('?'); if (queryStart !== -1) { var queryString = normalizedPath.substr(queryStart + 1, normalizedPath.length); normalizedPath = normalizedPath.substr(0, queryStart); queryParams = (0, _aureliaPath.parseQueryString)(queryString); } normalizedPath = decodeURI(normalizedPath); if (normalizedPath.charAt(0) !== '/') { normalizedPath = '/' + normalizedPath; } var pathLen = normalizedPath.length; if (pathLen > 1 && normalizedPath.charAt(pathLen - 1) === '/') { normalizedPath = normalizedPath.substr(0, pathLen - 1); isSlashDropped = true; } for (var i = 0, l = normalizedPath.length; i < l; i++) { states = recognizeChar(states, normalizedPath.charAt(i)); if (!states.length) { break; } } var solutions = []; for (var _i3 = 0, _l = states.length; _i3 < _l; _i3++) { if (states[_i3].handlers) { solutions.push(states[_i3]); } } states = sortSolutions(solutions); var state = solutions[0]; if (state && state.handlers) { if (isSlashDropped && state.regex.source.slice(-5) === '(.+)$') { normalizedPath = normalizedPath + '/'; } return findHandler(state, normalizedPath, queryParams); } return undefined; }; return RouteRecognizer; }(); var RecognizeResults = function RecognizeResults(queryParams) { this.splice = Array.prototype.splice; this.slice = Array.prototype.slice; this.push = Array.prototype.push; this.length = 0; this.queryParams = queryParams || {}; }; function parse(route, names, types, caseSensitive) { var normalizedRoute = route; if (route.charAt(0) === '/') { normalizedRoute = route.substr(1); } var results = []; var splitRoute = normalizedRoute.split('/'); for (var i = 0, ii = splitRoute.length; i < ii; ++i) { var segment = splitRoute[i]; var match = segment.match(/^:([^\/]+)$/); if (match) { results.push(new DynamicSegment(match[1])); names.push(match[1]); types.dynamics++; continue; } match = segment.match(/^\*([^\/]+)$/); if (match) { results.push(new StarSegment(match[1])); names.push(match[1]); types.stars++; } else if (segment === '') { results.push(new EpsilonSegment()); } else { results.push(new StaticSegment(segment, caseSensitive)); types.statics++; } } return results; } function sortSolutions(states) { return states.sort(function (a, b) { if (a.types.stars !== b.types.stars) { return a.types.stars - b.types.stars; } if (a.types.stars) { if (a.types.statics !== b.types.statics) { return b.types.statics - a.types.statics; } if (a.types.dynamics !== b.types.dynamics) { return b.types.dynamics - a.types.dynamics; } } if (a.types.dynamics !== b.types.dynamics) { return a.types.dynamics - b.types.dynamics; } if (a.types.statics !== b.types.statics) { return b.types.statics - a.types.statics; } return 0; }); } function recognizeChar(states, ch) { var nextStates = []; for (var i = 0, l = states.length; i < l; i++) { var state = states[i]; nextStates.push.apply(nextStates, state.match(ch)); } return nextStates; } function findHandler(state, path, queryParams) { 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]; var _names = _handler.names; var _params = {}; 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 }); } return result; } function addSegment(currentState, segment) { var state = currentState; segment.eachChar(function (ch) { state = state.put(ch); }); return state; } });