Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | 42x 42x 42x 42x 1x 41x 16x 2x 14x 41x 2x 39x 2x 39x 37x 37x 37x 15x 37x 70x 70x 70x 70x 70x 70x 70x 70x 70x 70x 70x | /**
* Path normalization for API routes
* Core logic - no Vite dependencies
*/
import { normalizePath as normalizePathUtil } from '../../shared/utils.js';
import { PARAM_PATTERN } from '../../shared/constants.js';
/**
* Converts a file path to a normalized HTTP route
*
* Examples:
* - users/[id].get.ts -> users/:id
* - posts/[...ids].get.ts -> posts/*ids
* - health.get.ts -> health
* - execute/index.post.ts -> execute (index treated as directory index)
*/
export function normalizeRoutePath(filePath: string): string {
// Remove extensions (.ts, .js) and HTTP method
let path = filePath
.replace(/\.(ts|js)$/, '')
.replace(/\.(get|post|put|patch|delete|head|options)$/, '');
// Normalize separators
path = path.replace(/\\/g, '/');
// Remove leading/trailing slashes (but preserve empty string for root route)
path = path.replace(/^\/+|\/+$/g, '');
// If path is empty, it means root route (e.g., health.get.ts)
if (!path) {
return '';
}
// Convert [id] to :id and [...ids] to *ids (catch-all)
path = path.replace(PARAM_PATTERN, (match, isCatchAll, paramName) => {
if (isCatchAll) {
return `*${paramName}`;
}
return `:${paramName}`;
});
if (path === 'index') {
return '';
}
if (path.endsWith('/index')) {
path = path.slice(0, -6);
}
return path;
}
/**
* Extracts parameters from a path pattern
* Example: "users/:id/posts/:postId" -> ["id", "postId"]
*/
export function extractParamsFromPattern(pattern: string): string[] {
const params: string[] = [];
const paramRegex = /[:*]([^/]+)/g;
let match;
while ((match = paramRegex.exec(pattern)) !== null) {
params.push(match[1]);
}
return params;
}
/**
* Converts a path pattern to regex for matching
* Example: "users/:id" -> /^\/users\/([^/]+)$/
* Example: "posts/*ids" -> /^\/posts\/(.*)$/
*/
export function patternToRegex(pattern: string): RegExp {
// Normalize pattern: empty route becomes '/', others add / at the beginning
let normalizedPattern = pattern === '' ? '/' : (pattern.startsWith('/') ? pattern : `/${pattern}`);
// First replace placeholders (before escaping)
// Replace *param (catch-all) with temporary placeholder
normalizedPattern = normalizedPattern.replace(/\*(\w+)/g, '__CATCHALL_$1__');
// Replace :param with temporary placeholder
normalizedPattern = normalizedPattern.replace(/:(\w+)/g, '__PARAM_$1__');
// Escape special characters
let regexStr = normalizedPattern.replace(/[.+?^${}()|[\]\\]/g, '\\$&');
// Restore placeholders as capture groups
regexStr = regexStr.replace(/__PARAM_\w+__/g, '([^/]+)');
regexStr = regexStr.replace(/__CATCHALL_(\w+)__/g, '(.*)');
// Ensure it starts and ends correctly
Eif (!regexStr.startsWith('^')) {
regexStr = '^' + regexStr;
}
Eif (!regexStr.endsWith('$')) {
regexStr = regexStr + '$';
}
return new RegExp(regexStr);
}
|