Last active
December 19, 2015 10:58
-
-
Save wiky/38da3eb0cbbb5976b33a to your computer and use it in GitHub Desktop.
url parser
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 匹配路由字符串参数的正则表达式。 | |
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