mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-07-13 03:27:39 +03:00
Cleanup Crossroads & Hasher and dropped Signals
This commit is contained in:
parent
32c3f1f059
commit
b26586f2ba
8 changed files with 133 additions and 584 deletions
246
vendors/routes/crossroads.js
vendored
246
vendors/routes/crossroads.js
vendored
|
|
@ -7,30 +7,7 @@
|
|||
|
||||
(global => {
|
||||
|
||||
// Helpers -----------
|
||||
//====================
|
||||
|
||||
//borrowed from AMD-utils
|
||||
function typecastValue(val) {
|
||||
var r;
|
||||
if (val === null || val === 'null') {
|
||||
r = null;
|
||||
} else if (val === 'true') {
|
||||
r = true;
|
||||
} else if (val === 'false') {
|
||||
r = false;
|
||||
} else if (val === undefined || val === 'undefined') {
|
||||
r = undefined;
|
||||
} else if (val === '' || isNaN(val)) {
|
||||
//isNaN('') returns false
|
||||
r = val;
|
||||
} else {
|
||||
//parseFloat(null || '') returns NaN
|
||||
r = parseFloat(val);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
const isFunction = obj => typeof obj === 'function';
|
||||
|
||||
// Crossroads --------
|
||||
//====================
|
||||
|
|
@ -38,33 +15,17 @@
|
|||
class Crossroads {
|
||||
|
||||
constructor() {
|
||||
this._routes = [];
|
||||
this.bypassed = new signals.Signal();
|
||||
this.routed = new global.signals.Signal();
|
||||
this.shouldTypecast = false;
|
||||
}
|
||||
this._routes = [];
|
||||
}
|
||||
|
||||
addRoute(pattern, callback, priority) {
|
||||
var route = new Route(pattern, callback, priority, this),
|
||||
routes = this._routes,
|
||||
n = routes.length;
|
||||
do { --n; } while (routes[n] && route._priority <= routes[n]._priority);
|
||||
routes.splice(n+1, 0, route);
|
||||
addRoute(pattern, callback) {
|
||||
var route = new Route(pattern, callback, this);
|
||||
this._routes.push(route);
|
||||
return route;
|
||||
}
|
||||
|
||||
removeRoute(route) {
|
||||
var i = this._routes.indexOf(route);
|
||||
if (i !== -1) {
|
||||
this._routes.splice(i, 1);
|
||||
}
|
||||
route._destroy();
|
||||
}
|
||||
|
||||
parse(request) {
|
||||
request = request || '';
|
||||
|
||||
var routes = this._getMatchedRoutes(request),
|
||||
var routes = this._getMatchedRoutes(request || ''),
|
||||
i = 0,
|
||||
n = routes.length,
|
||||
cur;
|
||||
|
|
@ -73,13 +34,10 @@
|
|||
//shold be incremental loop, execute routes in order
|
||||
while (i < n) {
|
||||
cur = routes[i];
|
||||
cur.route.matched.dispatch.apply(cur.route.matched, cur.params);
|
||||
cur.route.callback && cur.route.callback(...cur.params);
|
||||
cur.isFirst = !i;
|
||||
this.routed.dispatch(request, cur);
|
||||
i += 1;
|
||||
}
|
||||
} else {
|
||||
this.bypassed.dispatch(request);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -89,7 +47,8 @@
|
|||
n = routes.length,
|
||||
route;
|
||||
//should be decrement loop since higher priorities are added at the end of array
|
||||
while (route = routes[--n]) {
|
||||
while (n) {
|
||||
route = routes[--n];
|
||||
if ((!res.length || route.greedy) && route.match(request)) {
|
||||
res.push({
|
||||
route : route,
|
||||
|
|
@ -106,21 +65,17 @@
|
|||
|
||||
class Route {
|
||||
|
||||
constructor(pattern, callback, priority, router) {
|
||||
this.greedy = false;
|
||||
this.rules = void(0);
|
||||
var isRegexPattern = pattern instanceof RegExp;
|
||||
this._router = router;
|
||||
this._pattern = pattern;
|
||||
this._paramsIds = isRegexPattern ? null : patternLexer.getParamIds(this._pattern);
|
||||
this._optionalParamsIds = isRegexPattern ? null : patternLexer.getOptionalParamsIds(this._pattern);
|
||||
this._matchRegexp = isRegexPattern ? pattern : patternLexer.compilePattern(pattern);
|
||||
this.matched = new global.signals.Signal();
|
||||
if (callback) {
|
||||
this.matched.add(callback);
|
||||
}
|
||||
this._priority = priority || 0;
|
||||
}
|
||||
constructor(pattern, callback, router) {
|
||||
this.greedy = false;
|
||||
this.rules = {};
|
||||
var isRegexPattern = pattern instanceof RegExp;
|
||||
this._router = router;
|
||||
this._pattern = pattern;
|
||||
this._paramsIds = isRegexPattern ? null : patternLexer.getParamIds(this._pattern);
|
||||
this._optionalParamsIds = isRegexPattern ? null : patternLexer.getOptionalParamsIds(this._pattern);
|
||||
this._matchRegexp = isRegexPattern ? pattern : patternLexer.compilePattern(pattern);
|
||||
this.callback = isFunction(callback) ? callback : null;
|
||||
}
|
||||
|
||||
|
||||
match(request) {
|
||||
|
|
@ -128,16 +83,10 @@
|
|||
}
|
||||
|
||||
_validateParams(request) {
|
||||
var rules = this.rules,
|
||||
values = this._getParamsObject(request),
|
||||
key;
|
||||
for (key in rules) {
|
||||
// normalize_ isn't a validation rule... (#39)
|
||||
if(key !== 'normalize_' && rules.hasOwnProperty(key) && ! this._isValidParam(request, key, values)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
var values = this._getParamsObject(request);
|
||||
return 0 == Object.keys(this.rules).filter(key =>
|
||||
key !== 'normalize_' && !this._isValidParam(request, key, values)
|
||||
).length;
|
||||
}
|
||||
|
||||
_isValidParam(request, prop, values) {
|
||||
|
|
@ -154,7 +103,7 @@
|
|||
else if (Array.isArray(validationRule)) {
|
||||
isValid = validationRule.indexOf(val) !== -1;
|
||||
}
|
||||
else if (typeof validationRule === 'function') {
|
||||
else if (isFunction(validationRule)) {
|
||||
isValid = validationRule(val, request, values);
|
||||
}
|
||||
|
||||
|
|
@ -162,41 +111,29 @@
|
|||
}
|
||||
|
||||
_getParamsObject(request) {
|
||||
var shouldTypecast = this._router.shouldTypecast,
|
||||
values = patternLexer.getParamValues(request, this._matchRegexp, shouldTypecast),
|
||||
var values = patternLexer.getParamValues(request, this._matchRegexp),
|
||||
o = {},
|
||||
n = values.length;
|
||||
while (n--) {
|
||||
o[n] = values[n]; //for RegExp pattern and also alias to normal paths
|
||||
if (this._paramsIds) {
|
||||
o[this._paramsIds[n]] = values[n];
|
||||
}
|
||||
this._paramsIds && (o[this._paramsIds[n]] = values[n]);
|
||||
}
|
||||
o.request_ = shouldTypecast ? typecastValue(request) : request;
|
||||
o.request_ = request;
|
||||
o.vals_ = values;
|
||||
return o;
|
||||
}
|
||||
|
||||
_getParamsArray(request) {
|
||||
var norm = this.rules ? this.rules.normalize_ : null,
|
||||
var norm = this.rules.normalize_,
|
||||
params;
|
||||
if (norm && typeof norm === 'function') {
|
||||
if (isFunction(norm)) {
|
||||
params = norm(request, this._getParamsObject(request));
|
||||
} else {
|
||||
params = patternLexer.getParamValues(request, this._matchRegexp, this._router.shouldTypecast);
|
||||
params = patternLexer.getParamValues(request, this._matchRegexp);
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this._router.removeRoute(this);
|
||||
}
|
||||
|
||||
_destroy() {
|
||||
this.matched.dispose();
|
||||
this.matched = this._pattern = this._matchRegexp = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -204,74 +141,71 @@
|
|||
// Pattern Lexer ------
|
||||
//=====================
|
||||
|
||||
const
|
||||
ESCAPE_CHARS_REGEXP = /[\\.+*?^$[\](){}/'#]/g, //match chars that should be escaped on string regexp
|
||||
UNNECESSARY_SLASHES_REGEXP = /\/$/g, //trailing slash
|
||||
OPTIONAL_SLASHES_REGEXP = /([:}]|\w(?=\/))\/?(:)/g, //slash between `::` or `}:` or `\w:`. $1 = before, $2 = after
|
||||
REQUIRED_SLASHES_REGEXP = /([:}])\/?(\{)/g, //used to insert slash between `:{` and `}{`
|
||||
const
|
||||
ESCAPE_CHARS_REGEXP = /[\\.+*?^$[\](){}/'#]/g, //match chars that should be escaped on string regexp
|
||||
UNNECESSARY_SLASHES_REGEXP = /\/$/g, //trailing slash
|
||||
OPTIONAL_SLASHES_REGEXP = /([:}]|\w(?=\/))\/?(:)/g, //slash between `::` or `}:` or `\w:`. $1 = before, $2 = after
|
||||
REQUIRED_SLASHES_REGEXP = /([:}])\/?(\{)/g, //used to insert slash between `:{` and `}{`
|
||||
|
||||
REQUIRED_PARAMS_REGEXP = /\{([^}]+)\}/g, //match everything between `{ }`
|
||||
OPTIONAL_PARAMS_REGEXP = /:([^:]+):/g, //match everything between `: :`
|
||||
PARAMS_REGEXP = /(?:\{|:)([^}:]+)(?:\}|:)/g, //capture everything between `{ }` or `: :`
|
||||
REQUIRED_PARAMS_REGEXP = /\{([^}]+)\}/g, //match everything between `{ }`
|
||||
OPTIONAL_PARAMS_REGEXP = /:([^:]+):/g, //match everything between `: :`
|
||||
PARAMS_REGEXP = /(?:\{|:)([^}:]+)(?:\}|:)/g, //capture everything between `{ }` or `: :`
|
||||
|
||||
//used to save params during compile (avoid escaping things that
|
||||
//shouldn't be escaped).
|
||||
SAVE_REQUIRED_PARAMS = '__CR_RP__',
|
||||
SAVE_OPTIONAL_PARAMS = '__CR_OP__',
|
||||
SAVE_REQUIRED_SLASHES = '__CR_RS__',
|
||||
SAVE_OPTIONAL_SLASHES = '__CR_OS__',
|
||||
SAVED_REQUIRED_REGEXP = new RegExp(SAVE_REQUIRED_PARAMS, 'g'),
|
||||
SAVED_OPTIONAL_REGEXP = new RegExp(SAVE_OPTIONAL_PARAMS, 'g'),
|
||||
SAVED_OPTIONAL_SLASHES_REGEXP = new RegExp(SAVE_OPTIONAL_SLASHES, 'g'),
|
||||
SAVED_REQUIRED_SLASHES_REGEXP = new RegExp(SAVE_REQUIRED_SLASHES, 'g'),
|
||||
//used to save params during compile (avoid escaping things that
|
||||
//shouldn't be escaped).
|
||||
SAVE_REQUIRED_PARAMS = '__CR_RP__',
|
||||
SAVE_OPTIONAL_PARAMS = '__CR_OP__',
|
||||
SAVE_REQUIRED_SLASHES = '__CR_RS__',
|
||||
SAVE_OPTIONAL_SLASHES = '__CR_OS__',
|
||||
SAVED_REQUIRED_REGEXP = new RegExp(SAVE_REQUIRED_PARAMS, 'g'),
|
||||
SAVED_OPTIONAL_REGEXP = new RegExp(SAVE_OPTIONAL_PARAMS, 'g'),
|
||||
SAVED_OPTIONAL_SLASHES_REGEXP = new RegExp(SAVE_OPTIONAL_SLASHES, 'g'),
|
||||
SAVED_REQUIRED_SLASHES_REGEXP = new RegExp(SAVE_REQUIRED_SLASHES, 'g'),
|
||||
|
||||
|
||||
captureVals = (regex, pattern) => {
|
||||
var vals = [], match;
|
||||
while (match = regex.exec(pattern)) {
|
||||
vals.push(match[1]);
|
||||
}
|
||||
return vals;
|
||||
},
|
||||
captureVals = (regex, pattern) => {
|
||||
var vals = [], match;
|
||||
while (match = regex.exec(pattern)) {
|
||||
vals.push(match[1]);
|
||||
}
|
||||
return vals;
|
||||
},
|
||||
|
||||
tokenize = pattern => {
|
||||
//save chars that shouldn't be escaped
|
||||
return pattern.replace(OPTIONAL_SLASHES_REGEXP, '$1'+ SAVE_OPTIONAL_SLASHES +'$2')
|
||||
.replace(REQUIRED_SLASHES_REGEXP, '$1'+ SAVE_REQUIRED_SLASHES +'$2')
|
||||
.replace(OPTIONAL_PARAMS_REGEXP, SAVE_OPTIONAL_PARAMS)
|
||||
.replace(REQUIRED_PARAMS_REGEXP, SAVE_REQUIRED_PARAMS);
|
||||
},
|
||||
tokenize = pattern => {
|
||||
//save chars that shouldn't be escaped
|
||||
return pattern.replace(OPTIONAL_SLASHES_REGEXP, '$1'+ SAVE_OPTIONAL_SLASHES +'$2')
|
||||
.replace(REQUIRED_SLASHES_REGEXP, '$1'+ SAVE_REQUIRED_SLASHES +'$2')
|
||||
.replace(OPTIONAL_PARAMS_REGEXP, SAVE_OPTIONAL_PARAMS)
|
||||
.replace(REQUIRED_PARAMS_REGEXP, SAVE_REQUIRED_PARAMS);
|
||||
},
|
||||
|
||||
untokenize = pattern => {
|
||||
return pattern.replace(SAVED_OPTIONAL_SLASHES_REGEXP, '\\/?')
|
||||
.replace(SAVED_REQUIRED_SLASHES_REGEXP, '\\/')
|
||||
.replace(SAVED_OPTIONAL_REGEXP, '([^\\/]+)?/?')
|
||||
.replace(SAVED_REQUIRED_REGEXP, '([^\\/]+)');
|
||||
},
|
||||
untokenize = pattern => {
|
||||
return pattern.replace(SAVED_OPTIONAL_SLASHES_REGEXP, '\\/?')
|
||||
.replace(SAVED_REQUIRED_SLASHES_REGEXP, '\\/')
|
||||
.replace(SAVED_OPTIONAL_REGEXP, '([^\\/]+)?/?')
|
||||
.replace(SAVED_REQUIRED_REGEXP, '([^\\/]+)');
|
||||
},
|
||||
|
||||
patternLexer = {
|
||||
getParamIds : pattern => captureVals(PARAMS_REGEXP, pattern),
|
||||
getOptionalParamsIds : pattern => captureVals(OPTIONAL_PARAMS_REGEXP, pattern),
|
||||
getParamValues : (request, regexp, shouldTypecast) => {
|
||||
var vals = regexp.exec(request);
|
||||
if (vals) {
|
||||
vals.shift();
|
||||
if (shouldTypecast) {
|
||||
vals = vals.map(v => typecastValue(v));
|
||||
}
|
||||
}
|
||||
return vals;
|
||||
},
|
||||
compilePattern : pattern => {
|
||||
pattern = pattern || '';
|
||||
if (pattern) {
|
||||
pattern = untokenize(
|
||||
tokenize(pattern.replace(UNNECESSARY_SLASHES_REGEXP, '')).replace(ESCAPE_CHARS_REGEXP, '\\$&')
|
||||
);
|
||||
}
|
||||
return new RegExp('^'+ pattern + '/?$'); //trailing slash is optional
|
||||
}
|
||||
};
|
||||
patternLexer = {
|
||||
getParamIds : pattern => captureVals(PARAMS_REGEXP, pattern),
|
||||
getOptionalParamsIds : pattern => captureVals(OPTIONAL_PARAMS_REGEXP, pattern),
|
||||
getParamValues : (request, regexp) => {
|
||||
var vals = regexp.exec(request);
|
||||
if (vals) {
|
||||
vals.shift();
|
||||
}
|
||||
return vals;
|
||||
},
|
||||
compilePattern : pattern => {
|
||||
pattern = pattern || '';
|
||||
if (pattern) {
|
||||
pattern = untokenize(
|
||||
tokenize(pattern.replace(UNNECESSARY_SLASHES_REGEXP, '')).replace(ESCAPE_CHARS_REGEXP, '\\$&')
|
||||
);
|
||||
}
|
||||
return new RegExp('^'+ pattern + '/?$'); //trailing slash is optional
|
||||
}
|
||||
};
|
||||
|
||||
global.Crossroads = Crossroads;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue