/**
* @summary path-utilities
* @version 3.0.0
* @since 1.0.0
* @author Arian Khosravi <arian.khosravi@aofl.com>
*/
/**
* @memberof module:@aofl/router
* @private
* @type {RegExp}
*/
const DYNAMIC_PATH_REGEX = /:([^/\s]*)(\/?)/ig;
/**
* @memberof module:@aofl/router
* @private
* @type {RegExp}
*/
const CLEAN_PATH_REGEX = /[#?].*/i;
/**
* @memberof module:@aofl/router
* @private
* @type {RegExp}
*/
const TRAILING_SLASH_REGEX = /\/$/i;
/**
* @memberof module:@aofl/router
* @private
* @type {RegExp}
*/
const LEADING_SLASH_REGEX = /^\//i;
/**
* PathUtils implementation
* @memberof module:@aofl/router
*/
class PathUtils {
/**
* @param {String} _path
* @return {Object}
*/
static getRegex(_path) {
const path = PathUtils.removeTrailingSlash(PathUtils.cleanPath(_path));
let regexStr = '';
let matches = DYNAMIC_PATH_REGEX.exec(path);
const keys = [];
if (matches === null) {
regexStr = path;
} else {
let nextMatchIndex = 0;
while (matches) {
regexStr += path.substring(nextMatchIndex, matches.index) + '([^\\/\\s]*)' + matches[2];
nextMatchIndex = matches.index + matches[0].length;
keys.push(matches[1]);
matches = DYNAMIC_PATH_REGEX.exec(path);
}
regexStr += path.substr(nextMatchIndex);
}
const regex = new RegExp('^' + regexStr + '$');
return {
regex,
parse(p) {
if (keys.length === 0) return {};
const cleanPath = PathUtils.removeTrailingSlash(PathUtils.cleanPath(p));
const pathMatches = regex.exec(cleanPath);
return keys.reduce((acc, key, index) => {
acc[key] = pathMatches[index + 1];
return acc;
}, {});
}
};
}
/**
* @param {*} path
* @return {String}
* @throws {Error}
*/
static cleanPath(path) {
return path.replace(CLEAN_PATH_REGEX, '');
}
/**
* @param {String} str
* @return {String}
*/
static removeTrailingSlash(str) {
if (str === '/') return str;
return str && str.replace(TRAILING_SLASH_REGEX, '');
}
/**
* @param {String} str
* @return {String}
*/
static removeLeadingSlash(str) {
if (str === '/') return str;
return str && str.replace(LEADING_SLASH_REGEX, '');
}
/**
* Creates an array of url path segments from a url string
*
* @param {String} path
* @return {Array}
*/
static getPathSegments(path) {
return path.split('/').filter((item) => item);
}
/**
* Evaluates whether the given segment is dynamic
*
* @param {String} segment
* @return {Boolean}
*/
static isDynamicSegment(segment) {
return segment.indexOf(':') > -1;
}
/**
* Enumerates the number of matching segments in the given arrays of strings
* @param {Array} segmentsA
* @param {Array} segmentsB
* @return {Number}
*/
static matchingSegmentsCount(segmentsA, segmentsB) {
let matches = 0;
for (let i = 0; i < segmentsA.length && i < segmentsB.length; i++) {
/* istanbul ignore else */
if (segmentsA[i] === segmentsB[i]) {
matches++;
} else if (!PathUtils.isDynamicSegment(segmentsA[i]) && !PathUtils.isDynamicSegment(segmentsB[i])) {
// Both segments are static and do not match.
// This immediately disqualifies this as a matching route
matches = -1;
break;
}
}
return matches;
}
}
export default PathUtils;