Skip to content

Instantly share code, notes, and snippets.

@wiky
Last active December 19, 2015 10:58
Show Gist options
  • Save wiky/38da3eb0cbbb5976b33a to your computer and use it in GitHub Desktop.
Save wiky/38da3eb0cbbb5976b33a to your computer and use it in GitHub Desktop.
url parser
// 匹配路由字符串参数的正则表达式。
var optionalParam = /\((.*?)\)/g;
var namedParam = /(\(\?)?(:\w+)(?:\\\[([^\]]+)\\\])?/g;
var itemParam = /:(\w+)(\?)?(?:\[([^\]]+)\])?/g;
var splatParam = /\*/g;
var escapeRegExp = /[\-{}\[\]+?.,\\\^$|#\s]/g;
/**
* 路由规则转为正则表达式
*
* @param {String} route 路由规则字符串
* @return {RegExp} 正则表达式对象
*/
var routeToRegExp = function(route) {
route = route
.replace(escapeRegExp, '\\$&')
.replace(optionalParam, function(match, items) {
items = items
.replace(/(?:\/|\\\|)?:(\w+)/g, '~~(?:$`$&)')
.split('~~').reverse().join('|')
.replace(namedParam, '(?:$2)?');
return '(?:' + items + '\/?)?';
})
.replace(namedParam, function(match, optional, param, enums) {
enums = enums && enums.split(/\s*\\,\s*/).join('|');
enums = enums ? '(' + enums + ')' : '';
return optional ? match : (enums || '([^\/]+)');
})
.replace(splatParam, '(.*?)');
return new RegExp('^' + route + '$');
};
/**
* 提取路由参数
*
* @param {String} route 路由规则
* @param {String} fragment URL片段
*/
var extractParameters = function(route, fragment) {
var params = (routeToRegExp(route).exec(fragment) || []).slice(1),
keys = extractParameterNames(route)[0],
ret = {};
for (var i = 0; i < params.length; i++) {
if (params[i]) {
ret[keys[i]] = decodeURIComponent(params[i]);
}
}
return ret;
};
/**
* 提取路由参数名
*
* @param {String} route 路由规则
*/
var extractParameterNames = function(route) {
var keys = [],
opts = {};
// true表示必选,false表示可选
route = route
.replace(optionalParam, function(match, items) {
items = items
.replace(/(?:\/|\\\|)?:(\w+)/g, '~~(?:$`$&)')
.split('~~').reverse().join('|')
.replace(namedParam, '$2?');
return items;
})
.replace(itemParam, function(match, itemName, optional) {
keys.push(itemName);
opts[itemName] = !optional;
return match;
});
console.log(opts);
return [keys, opts];
};
var backfillParameters = function(route, params) {
params = params || {};
route = route
.replace(optionalParam, function(match, items) {
var hasValueItems = [];
items = items.replace(itemParam, function(match, itemName) {
if (typeof params[itemName] !== 'undefined') {
hasValueItems.push(itemName);
}
return match + '?';
});
return hasValueItems.length > 0 ? items : '';
})
.replace(itemParam, function(match, itemName, optional, enums) {
enums = enums && enums.split(/\s*,\s*/);
var value = encodeURIComponent(params[itemName] || ''),
inEnum = true;
if (enums) {
inEnum = false;
enums.forEach(function(item, i) {
if (value.toString() === item) {
inEnum = true;
}
});
}
// 可选参数为空时,可忽略;必选参数为空时,输出`undefined`;
// 必选参数带枚举的,值不在枚举范围内的,输出`undefined`
return (inEnum && value) || (optional ? '' : 'undefined');
});
return route;
};
// for test
var route = "listPage/:listType[a,bc](/:folderName|:currentPage)";
var path = 'listPage/bc/xx|123';
var reg = routeToRegExp(route);
var params = extractParameters(route, path);
console.log(params);
params.listType="bc";
delete params.folderName;
var newPath = backfillParameters(route, params);
console.log(newPath);
var params2 = extractParameters(route, newPath);
console.log('params2', params2);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment