proxy-based Twister client written with react-js
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

"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;