You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
153 lines
4.1 KiB
153 lines
4.1 KiB
"use strict"; |
|
|
|
var invariant = require("react/lib/invariant"); |
|
var objectAssign = require("object-assign"); |
|
var qs = require("qs"); |
|
|
|
var paramCompileMatcher = /:([a-zA-Z_$][a-zA-Z0-9_$]*)|[*.()\[\]\\+|{}^$]/g; |
|
var paramInjectMatcher = /:([a-zA-Z_$][a-zA-Z0-9_$?]*[?]?)|[*]/g; |
|
var paramInjectTrailingSlashMatcher = /\/\/\?|\/\?\/|\/\?/g; |
|
var queryMatcher = /\?(.*)$/; |
|
|
|
var _compiledPatterns = {}; |
|
|
|
function compilePattern(pattern) { |
|
if (!(pattern in _compiledPatterns)) { |
|
var paramNames = []; |
|
var source = pattern.replace(paramCompileMatcher, function (match, paramName) { |
|
if (paramName) { |
|
paramNames.push(paramName); |
|
return "([^/?#]+)"; |
|
} else if (match === "*") { |
|
paramNames.push("splat"); |
|
return "(.*?)"; |
|
} else { |
|
return "\\" + match; |
|
} |
|
}); |
|
|
|
_compiledPatterns[pattern] = { |
|
matcher: new RegExp("^" + source + "$", "i"), |
|
paramNames: paramNames |
|
}; |
|
} |
|
|
|
return _compiledPatterns[pattern]; |
|
} |
|
|
|
var PathUtils = { |
|
|
|
/** |
|
* Returns true if the given path is absolute. |
|
*/ |
|
isAbsolute: function isAbsolute(path) { |
|
return path.charAt(0) === "/"; |
|
}, |
|
|
|
/** |
|
* Joins two URL paths together. |
|
*/ |
|
join: function join(a, b) { |
|
return a.replace(/\/*$/, "/") + b; |
|
}, |
|
|
|
/** |
|
* Returns an array of the names of all parameters in the given pattern. |
|
*/ |
|
extractParamNames: function extractParamNames(pattern) { |
|
return compilePattern(pattern).paramNames; |
|
}, |
|
|
|
/** |
|
* Extracts the portions of the given URL path that match the given pattern |
|
* and returns an object of param name => value pairs. Returns null if the |
|
* pattern does not match the given path. |
|
*/ |
|
extractParams: function extractParams(pattern, path) { |
|
var _compilePattern = compilePattern(pattern); |
|
|
|
var matcher = _compilePattern.matcher; |
|
var paramNames = _compilePattern.paramNames; |
|
|
|
var match = path.match(matcher); |
|
|
|
if (!match) { |
|
return null; |
|
}var params = {}; |
|
|
|
paramNames.forEach(function (paramName, index) { |
|
params[paramName] = match[index + 1]; |
|
}); |
|
|
|
return params; |
|
}, |
|
|
|
/** |
|
* Returns a version of the given route path with params interpolated. Throws |
|
* if there is a dynamic segment of the route path for which there is no param. |
|
*/ |
|
injectParams: function injectParams(pattern, params) { |
|
params = params || {}; |
|
|
|
var splatIndex = 0; |
|
|
|
return pattern.replace(paramInjectMatcher, function (match, paramName) { |
|
paramName = paramName || "splat"; |
|
|
|
// If param is optional don't check for existence |
|
if (paramName.slice(-1) === "?") { |
|
paramName = paramName.slice(0, -1); |
|
|
|
if (params[paramName] == null) return ""; |
|
} else { |
|
invariant(params[paramName] != null, "Missing \"%s\" parameter for path \"%s\"", paramName, pattern); |
|
} |
|
|
|
var segment; |
|
if (paramName === "splat" && Array.isArray(params[paramName])) { |
|
segment = params[paramName][splatIndex++]; |
|
|
|
invariant(segment != null, "Missing splat # %s for path \"%s\"", splatIndex, pattern); |
|
} else { |
|
segment = params[paramName]; |
|
} |
|
|
|
return segment; |
|
}).replace(paramInjectTrailingSlashMatcher, "/"); |
|
}, |
|
|
|
/** |
|
* Returns an object that is the result of parsing any query string contained |
|
* in the given path, null if the path contains no query string. |
|
*/ |
|
extractQuery: function extractQuery(path) { |
|
var match = path.match(queryMatcher); |
|
return match && qs.parse(match[1]); |
|
}, |
|
|
|
/** |
|
* Returns a version of the given path without the query string. |
|
*/ |
|
withoutQuery: function withoutQuery(path) { |
|
return path.replace(queryMatcher, ""); |
|
}, |
|
|
|
/** |
|
* Returns a version of the given path with the parameters in the given |
|
* query merged into the query string. |
|
*/ |
|
withQuery: function withQuery(path, query) { |
|
var existingQuery = PathUtils.extractQuery(path); |
|
|
|
if (existingQuery) query = query ? objectAssign(existingQuery, query) : existingQuery; |
|
|
|
var queryString = qs.stringify(query, { arrayFormat: "brackets" }); |
|
|
|
if (queryString) { |
|
return PathUtils.withoutQuery(path) + "?" + queryString; |
|
}return PathUtils.withoutQuery(path); |
|
} |
|
|
|
}; |
|
|
|
module.exports = PathUtils; |