UNPKG

@gati-framework/runtime

Version:

Gati runtime execution engine for running handler-based applications

106 lines 3.15 kB
/** * @module runtime/route-parser * @description Route pattern parsing and compilation for Gati framework */ /** * Parse a route path pattern and compile it into a RoutePattern * * @param path - Route path pattern (e.g., /users/:id/posts/:postId) * @returns Compiled route pattern * * @example * ```typescript * const pattern = parseRoute('/users/:id'); * // pattern.regex matches paths like /users/123 * // pattern.paramNames = ['id'] * ``` */ export function parseRoute(path) { // Normalize path const normalizedPath = normalizePath(path); // Extract parameter names const paramNames = []; // Convert path pattern to regex // Replace :param with named capture groups const regexPattern = normalizedPath.replace(/:([a-zA-Z_][a-zA-Z0-9_]*)/g, (_, paramName) => { paramNames.push(paramName); return '([^/]+)'; // Match any character except / }); // Create regex with exact match const regex = new RegExp(`^${regexPattern}$`); return { regex, paramNames, path: normalizedPath, }; } /** * Normalize a route path * - Ensures path starts with / * - Removes trailing slash (unless it's the root path) * - Removes duplicate slashes * * @param path - Path to normalize * @returns Normalized path */ export function normalizePath(path) { // Ensure path starts with / let normalized = path.startsWith('/') ? path : `/${path}`; // Remove duplicate slashes normalized = normalized.replace(/\/+/g, '/'); // Remove trailing slash (except for root) if (normalized.length > 1 && normalized.endsWith('/')) { normalized = normalized.slice(0, -1); } return normalized; } /** * Extract path parameters from a matched path * * @param path - Actual request path * @param pattern - Compiled route pattern * @returns Extracted parameters or null if no match * * @example * ```typescript * const pattern = parseRoute('/users/:id'); * const params = extractParams('/users/123', pattern); * // params = { id: '123' } * ``` */ export function extractParams(path, pattern) { const normalizedPath = normalizePath(path); const match = pattern.regex.exec(normalizedPath); if (!match) { return null; } // Extract parameters from regex capture groups const params = {}; pattern.paramNames.forEach((name, index) => { // Capture groups start at index 1 (0 is the full match) const value = match[index + 1]; if (value !== undefined) { params[name] = decodeURIComponent(value); } }); return params; } /** * Check if a path matches a route pattern * * @param path - Request path to test * @param pattern - Route pattern to match against * @returns true if path matches pattern * * @example * ```typescript * const pattern = parseRoute('/users/:id'); * matchPath('/users/123', pattern); // true * matchPath('/posts/123', pattern); // false * ``` */ export function matchPath(path, pattern) { const normalizedPath = normalizePath(path); return pattern.regex.test(normalizedPath); } //# sourceMappingURL=route-parser.js.map