/** * @file Path Extractor for Route Discovery * @description Extracts URL paths from file system structure using convention-based parsing. * Supports Next.js-style file naming conventions including dynamic routes, catch-all routes, * route groups, and parallel routes. * * @module @/lib/routing/discovery/path-extractor * * This module provides: * - File path to URL path conversion * - Dynamic segment extraction * - Route parameter parsing * - Path hierarchy analysis * - Convention-based naming support * * @example * ```typescript * import { extractPathFromFile, parseSegments } from '@/lib/routing/discovery/path-extractor'; * * const urlPath = extractPathFromFile('users/[id]/posts/[postId]/page.tsx'); * console.log(urlPath); // '/users/:id/posts/:postId' * * const segments = parseSegments('users/[id]/posts'); * console.log(segments); * // [ * // { type: 'static', value: 'users', raw: 'users' }, * // { type: 'dynamic', value: 'id', raw: '[id]' }, * // { type: 'static', value: 'posts', raw: 'posts' }, * // ] * ``` */ /** * Types of path segments that can be extracted */ export type SegmentType = 'static' | 'dynamic' | 'optional' | 'catch-all' | 'optional-catch-all' | 'group' | 'parallel' | 'intercepting'; /** * Parsed path segment with full metadata */ export interface ParsedSegment { /** Type of segment */ readonly type: SegmentType; /** Extracted value (parameter name or static value) */ readonly value: string; /** Original raw segment string */ readonly raw: string; /** Whether segment is optional */ readonly optional: boolean; /** Position in the path */ readonly position: number; /** Constraint type (if any) */ readonly constraint?: SegmentConstraint; } /** * Constraint that can be applied to dynamic segments */ export interface SegmentConstraint { /** Constraint type */ readonly type: 'regex' | 'enum' | 'custom'; /** Constraint pattern or values */ readonly pattern: string | readonly string[]; /** Validation function name */ readonly validator?: string; } /** * Extracted path information */ export interface ExtractedPath { /** The URL path pattern */ readonly urlPath: string; /** All segments parsed */ readonly segments: readonly ParsedSegment[]; /** Parameter names extracted */ readonly params: readonly string[]; /** Optional parameters */ readonly optionalParams: readonly string[]; /** Whether path has catch-all */ readonly hasCatchAll: boolean; /** Whether path has optional catch-all */ readonly hasOptionalCatchAll: boolean; /** Route groups this path belongs to */ readonly groups: readonly string[]; /** Parallel slots in this path */ readonly parallelSlots: readonly string[]; /** Nesting depth */ readonly depth: number; /** Whether this is an index route */ readonly isIndex: boolean; /** Whether this is a layout route */ readonly isLayout: boolean; } /** * Path extraction configuration */ export interface PathExtractorConfig { /** File names that represent index routes */ readonly indexFileNames: readonly string[]; /** File names that represent layout routes */ readonly layoutFileNames: readonly string[]; /** Strip these extensions from file names */ readonly stripExtensions: readonly string[]; /** Segment naming convention */ readonly convention: 'nextjs' | 'remix' | 'custom'; /** Custom segment parser */ readonly customParser?: (segment: string) => ParsedSegment | null; /** Feature flag for advanced features */ readonly featureFlag?: string; } /** * Path hierarchy node */ export interface PathNode { /** Segment at this level */ readonly segment: ParsedSegment; /** Full path to this node */ readonly path: string; /** Parent node (if any) */ readonly parent: PathNode | null; /** Child nodes */ readonly children: readonly PathNode[]; /** Associated files */ readonly files: readonly string[]; } /** * Default path extractor configuration */ export declare const DEFAULT_EXTRACTOR_CONFIG: PathExtractorConfig; /** * Parse a single path segment into a ParsedSegment * * @param segment - Raw segment string * @param position - Position in the path * @param config - Extractor configuration * @returns Parsed segment or null if invalid * * @example * ```typescript * parseSegment('[id]', 0); * // { type: 'dynamic', value: 'id', raw: '[id]', optional: false, position: 0 } * * parseSegment('[[...slug]]', 1); * // { type: 'optional-catch-all', value: 'slug', raw: '[[...slug]]', optional: true, position: 1 } * ``` */ export declare function parseSegment(segment: string, position: number, config?: PathExtractorConfig): ParsedSegment | null; /** * Parse all segments from a path string * * @param path - File path to parse (e.g., 'users/[id]/posts') * @param config - Extractor configuration * @returns Array of parsed segments * * @example * ```typescript * const segments = parseSegments('users/[id]/posts/[[...slug]]'); * // Returns 4 segments: static, dynamic, static, optional-catch-all * ``` */ export declare function parseSegments(path: string, config?: PathExtractorConfig): readonly ParsedSegment[]; /** * Convert parsed segments to a URL path pattern * * @param segments - Parsed segments * @returns URL path string (e.g., '/users/:id/posts') */ export declare function segmentsToUrlPath(segments: readonly ParsedSegment[]): string; /** * Extract full path information from a file path * * @param filePath - File path relative to routes directory * @param config - Extractor configuration * @returns Extracted path information * * @example * ```typescript * const extracted = extractPathFromFile('users/[id]/posts/[postId]/page.tsx'); * console.log(extracted.urlPath); // '/users/:id/posts/:postId' * console.log(extracted.params); // ['id', 'postId'] * console.log(extracted.isIndex); // true (page.tsx is index) * ``` */ export declare function extractPathFromFile(filePath: string, config?: PathExtractorConfig): ExtractedPath; /** * Extract parameters from a URL given a path pattern * * Delegates to core path utilities for the actual extraction. * * @param pattern - URL pattern (e.g., '/users/:id/posts/:postId') * @param url - Actual URL to extract from (e.g., '/users/123/posts/456') * @returns Extracted parameters or null if no match * * @example * ```typescript * const params = extractParamsFromUrl('/users/:id', '/users/123'); * console.log(params); // { id: '123' } * ``` */ export declare function extractParamsFromUrl(pattern: string, url: string): Record | null; /** * Build a path hierarchy tree from multiple file paths * * @param filePaths - Array of file paths * @param config - Extractor configuration * @returns Root nodes of the path hierarchy * * @example * ```typescript * const tree = buildPathTree([ * 'users/page.tsx', * 'users/[id]/page.tsx', * 'users/[id]/posts/page.tsx', * ]); * // Returns hierarchical tree structure * ``` */ export declare function buildPathTree(filePaths: readonly string[], config?: PathExtractorConfig): readonly PathNode[]; /** * Find the common ancestor path for multiple paths * * @param paths - Array of URL paths * @returns Common ancestor path or '/' if none */ export declare function findCommonAncestor(paths: readonly string[]): string; /** * Check if one path is a child of another * * Delegates to core path utilities. * * @param childPath - Potential child path * @param parentPath - Potential parent path * @returns True if childPath is nested under parentPath */ export declare function isChildPath(childPath: string, parentPath: string): boolean; /** * Get the relative path from parent to child * * @param childPath - Child path * @param parentPath - Parent path * @returns Relative path or null if not a child */ export declare function getRelativePath(childPath: string, parentPath: string): string | null; /** * Validate that a path pattern is well-formed * * @param pattern - URL path pattern to validate * @returns Validation result with any errors */ export declare function validatePathPattern(pattern: string): { readonly isValid: boolean; readonly errors: readonly string[]; }; /** * Compare two path patterns for specificity (more specific = higher) * * Delegates to core path utilities for specificity calculation. * * @param a - First path pattern * @param b - Second path pattern * @returns Negative if a < b, positive if a > b, 0 if equal */ export declare function comparePathSpecificity(a: string, b: string): number;