@dbs-portal/tool-mock
Version:
API mocking toolkit using MSW for DBS Portal development workflows
227 lines • 5.94 kB
JavaScript
/**
* URL utilities for mock handlers
*/
/**
* Parse URL parameters from a path pattern
*/
export function parseUrlParams(url, pattern) {
const params = {};
// Convert pattern to regex
const regexPattern = pattern
.replace(/:[^/]+/g, '([^/]+)')
.replace(/\*/g, '(.*)');
const regex = new RegExp(`^${regexPattern}$`);
const match = url.match(regex);
if (!match) {
return params;
}
// Extract parameter names from pattern
const paramNames = pattern.match(/:[^/]+/g) || [];
// Map captured groups to parameter names
for (let i = 0; i < paramNames.length; i++) {
const paramName = paramNames[i]?.substring(1); // Remove ':'
if (!paramName)
continue;
const paramValue = match[i + 1];
if (paramValue !== undefined) {
params[paramName] = decodeURIComponent(paramValue);
}
}
return params;
}
/**
* Parse query parameters from URL
*/
export function parseQueryParams(url) {
const urlObj = new URL(url);
const params = {};
for (const [key, value] of urlObj.searchParams.entries()) {
params[key] = value;
}
return params;
}
/**
* Check if URL matches a pattern
*/
export function matchesUrl(url, options) {
const { pattern, caseSensitive = false } = options;
let urlToMatch = caseSensitive ? url : url.toLowerCase();
if (typeof pattern === 'string') {
let patternToMatch = caseSensitive ? pattern : pattern.toLowerCase();
// Convert simple pattern to regex
if (pattern.includes(':') || pattern.includes('*')) {
const regexPattern = patternToMatch
.replace(/:[^/]+/g, '[^/]+')
.replace(/\*/g, '.*');
const regex = new RegExp(`^${regexPattern}$`);
return regex.test(urlToMatch);
}
return urlToMatch.includes(patternToMatch);
}
return pattern.test(url);
}
/**
* Extract path from URL
*/
export function extractPath(url) {
try {
const urlObj = new URL(url);
return urlObj.pathname;
}
catch {
// If URL is invalid, assume it's already a path
return url.split('?')[0] || '';
}
}
/**
* Build URL with parameters
*/
export function buildUrl(baseUrl, path, params, query) {
let url = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
let finalPath = path.startsWith('/') ? path : `/${path}`;
// Replace path parameters
if (params) {
for (const [key, value] of Object.entries(params)) {
finalPath = finalPath.replace(`:${key}`, encodeURIComponent(value));
}
}
url += finalPath;
// Add query parameters
if (query && Object.keys(query).length > 0) {
const searchParams = new URLSearchParams();
for (const [key, value] of Object.entries(query)) {
searchParams.append(key, value);
}
url += `?${searchParams.toString()}`;
}
return url;
}
/**
* Normalize URL for comparison
*/
export function normalizeUrl(url) {
try {
const urlObj = new URL(url);
// Remove trailing slash from pathname
if (urlObj.pathname.endsWith('/') && urlObj.pathname.length > 1) {
urlObj.pathname = urlObj.pathname.slice(0, -1);
}
// Sort query parameters
const sortedParams = new URLSearchParams();
const params = Array.from(urlObj.searchParams.entries()).sort();
for (const [key, value] of params) {
sortedParams.append(key, value);
}
urlObj.search = sortedParams.toString();
return urlObj.toString();
}
catch {
return url;
}
}
/**
* Check if URL is absolute
*/
export function isAbsoluteUrl(url) {
try {
new URL(url);
return true;
}
catch {
return false;
}
}
/**
* Join URL paths
*/
export function joinPaths(...paths) {
return paths
.map((path, index) => {
if (index === 0) {
return path.replace(/\/+$/, '');
}
return path.replace(/^\/+/, '').replace(/\/+$/, '');
})
.filter(Boolean)
.join('/');
}
/**
* Get base URL from full URL
*/
export function getBaseUrl(url) {
try {
const urlObj = new URL(url);
return `${urlObj.protocol}//${urlObj.host}`;
}
catch {
return '';
}
}
/**
* Parse URL into components
*/
export function parseUrl(url) {
try {
const urlObj = new URL(url);
return {
protocol: urlObj.protocol,
host: urlObj.host,
hostname: urlObj.hostname,
port: urlObj.port,
pathname: urlObj.pathname,
search: urlObj.search,
hash: urlObj.hash,
params: parseQueryParams(url),
};
}
catch {
const [pathname, search = ''] = url.split('?');
const [pathOnly, hash = ''] = (pathname || '').split('#');
return {
pathname: pathOnly || '',
search: search ? `?${search}` : '',
hash: hash ? `#${hash}` : '',
params: parseQueryParams(url),
};
}
}
/**
* Create URL matcher function
*/
export function createUrlMatcher(patterns) {
return (url) => {
return patterns.some(pattern => {
if (typeof pattern === 'string') {
return matchesUrl(url, { pattern });
}
return pattern.test(url);
});
};
}
/**
* Validate URL format
*/
export function isValidUrl(url) {
try {
new URL(url);
return true;
}
catch {
return false;
}
}
/**
* Convert relative URL to absolute
*/
export function toAbsoluteUrl(url, baseUrl) {
if (isAbsoluteUrl(url)) {
return url;
}
try {
return new URL(url, baseUrl).toString();
}
catch {
return url;
}
}
//# sourceMappingURL=url.js.map