-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
99 lines (86 loc) · 2.6 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
/**
* Copyright (c) 2013 Yahoo! Inc. All rights reserved.
* Copyrights licensed under the MIT License.
* See the accompanying LICENSE file for terms.
*/
/*jshint node:true*/
'use strict';
var SYMBOLS = /([.+*(){}\[\]\/])/g, //escape .+*(){}[]/ in name patterns
NAME_ID = /([:•])(\w+)/g, //extract :names or •names from patterns
NAME_RE = '([\\w.-]+)', //for final regex, to use in place of :names
SPOT_RE = '(\\S+)'; //for final regex, to use in place of •names
function makeout(names, vals) {
var out;
if(names.length) {
out = {};
names.forEach(function combine(name, i) {
out[name] = vals[i];
});
} else { //no names, so pattern was a regex-route; empty array if no parens
out = vals;
}
return out;
}
//convert string containing ":names" or "•names" to RegExp
function namer(nameroute, names) {
var pattern = nameroute.replace(SYMBOLS, '\\$1');
function partnamer(ignored, colon_or_spot, name) {
names.push(name); //save names to recombine later w/makeout
return colon_or_spot === ':' ? NAME_RE : SPOT_RE;
}
return pattern.replace(NAME_ID, partnamer);
}
function regexify(pattern, isregex, names) {
//possible pattern values:
// 1. RegExp object, 2. regex string, or 3. string to regexify
return pattern instanceof RegExp ?
pattern : new RegExp(isregex ? pattern : namer(pattern, names), 'i');
}
function compile(route) {
var names = [],
regex = regexify(route.pattern, route.isregex, names);
return {
names: names,
regex: regex,
param: route.param || []
};
}
function hasPattern(route) {
return ('pattern' in route) &&
('string' === typeof route.pattern || route.pattern instanceof RegExp);
}
/**
* @param {array} routes
*/
function Byway(routes) {
if (!(this instanceof Byway)) {
return new Byway(routes);
}
if(routes instanceof Array) {
this.routes = routes.filter(hasPattern).map(compile);
}
if(!this.routes || !this.routes.length) {
throw new Error('no valid routes');
}
}
/**
* @param {string} str
* @return {object|false}
*/
Byway.prototype.of = function(str) {
var found = false;
function match(route) {
found = route.regex.exec(str);
if(found) {
found = {
'input': found.input,
'param': route.param,
'parts': makeout(route.names, found.slice(1))
};
return true;
}
}
this.routes.some(match);
return found;
};
module.exports = Byway;