/** * @file Automatic Route File Discovery Scanner * @description Enterprise-grade automatic route file discovery with glob pattern matching, * intelligent caching, and comprehensive file system analysis. * * @module @/lib/routing/discovery/auto-scanner * * This module provides: * - Glob pattern-based file discovery * - Intelligent caching with TTL and invalidation * - Multi-root directory scanning * - File extension filtering * - Ignore pattern support * - Detailed scan statistics * * @example * ```typescript * import { AutoScanner, createAutoScanner } from '@/lib/routing/discovery/auto-scanner'; * * const scanner = createAutoScanner({ * roots: ['src/routes', 'src/features'], * extensions: ['.tsx', '.ts'], * ignore: ['**\/*.test.ts', '**\/__tests__/**'], * }); * * const result = await scanner.scan(); * console.log(`Found ${result.files.length} route files`); * ``` */ /** * File type classification for discovered files */ export type RouteFileType = 'page' | 'layout' | 'loading' | 'error' | 'not-found' | 'template' | 'default' | 'route' | 'middleware'; /** * Discovered file metadata */ export interface DiscoveredFile { /** Absolute file path */ readonly absolutePath: string; /** Path relative to the scan root */ readonly relativePath: string; /** File name without extension */ readonly name: string; /** File extension (e.g., '.tsx') */ readonly extension: string; /** Classified file type */ readonly fileType: RouteFileType; /** Directory containing the file */ readonly directory: string; /** Nesting depth from scan root */ readonly depth: number; /** File modification timestamp */ readonly modifiedAt: number; /** File size in bytes */ readonly size: number; } /** * Glob pattern configuration for file matching */ export interface GlobPattern { /** Pattern string (supports ** and * wildcards) */ readonly pattern: string; /** Whether this is an include or exclude pattern */ readonly type: 'include' | 'exclude'; /** Priority for pattern matching (higher = evaluated first) */ readonly priority: number; } /** * Auto scanner configuration */ export interface AutoScannerConfig { /** Root directories to scan */ readonly roots: readonly string[]; /** File extensions to include */ readonly extensions: readonly string[]; /** Glob patterns for ignoring files/directories */ readonly ignore: readonly string[]; /** Additional glob patterns for including specific files */ readonly include?: readonly string[]; /** Enable deep scanning (follow symlinks) */ readonly followSymlinks?: boolean; /** Maximum directory depth to scan */ readonly maxDepth?: number; /** Enable caching of scan results */ readonly cache?: boolean; /** Cache TTL in milliseconds */ readonly cacheTTL?: number; /** Concurrency level for parallel scanning */ readonly concurrency?: number; /** Custom file type classifier */ readonly classifyFile?: (filename: string) => RouteFileType; /** Feature flag to enable/disable scanner */ readonly featureFlag?: string; } /** * Scan result with comprehensive metadata */ export interface ScanResult { /** Discovered files */ readonly files: readonly DiscoveredFile[]; /** Scan statistics */ readonly stats: ScanStatistics; /** Any errors encountered during scanning */ readonly errors: readonly ScanError[]; /** Whether result came from cache */ readonly fromCache: boolean; /** Timestamp when scan completed */ readonly scannedAt: number; } /** * Scan statistics for monitoring and debugging */ export interface ScanStatistics { /** Total files discovered */ readonly totalFiles: number; /** Total directories scanned */ readonly totalDirectories: number; /** Files ignored by patterns */ readonly ignoredFiles: number; /** Scan duration in milliseconds */ readonly durationMs: number; /** Breakdown by file type */ readonly byFileType: Record; /** Breakdown by extension */ readonly byExtension: Record; /** Maximum depth reached */ readonly maxDepthReached: number; /** Average file size */ readonly avgFileSize: number; } /** * Error encountered during scanning */ export interface ScanError { /** Error type */ readonly type: 'permission' | 'not-found' | 'symlink' | 'unknown'; /** Path that caused the error */ readonly path: string; /** Error message */ readonly message: string; /** Original error (if available) */ readonly originalError?: Error; } /** * Default scanner configuration */ export declare const DEFAULT_SCANNER_CONFIG: AutoScannerConfig; /** * Classify a file based on its name * * @param filename - The filename to classify * @returns The classified file type */ export declare function classifyFileType(filename: string): RouteFileType; /** * Convert a glob pattern to a RegExp * * @param pattern - Glob pattern string * @returns Compiled RegExp */ export declare function globToRegex(pattern: string): RegExp; /** * Check if a path matches any of the given patterns * * @param path - Path to check * @param patterns - Patterns to match against * @returns True if path matches any pattern */ export declare function matchesPatterns(path: string, patterns: readonly string[]): boolean; /** * Automatic route file scanner with caching and parallel scanning support * * @example * ```typescript * const scanner = new AutoScanner({ * roots: ['src/routes'], * extensions: ['.tsx'], * }); * * const result = await scanner.scan(); * for (const file of result.files) { * console.log(`${file.fileType}: ${file.relativePath}`); * } * ``` */ export declare class AutoScanner { private readonly config; private cache; private isScanning; private pendingScan; /** * Create a new AutoScanner instance * * @param config - Scanner configuration (merged with defaults) */ constructor(config?: Partial); /** * Get the current configuration */ getConfig(): Readonly; /** * Perform a file system scan * * @param forceRefresh - Skip cache and perform fresh scan * @returns Scan result with discovered files */ scan(forceRefresh?: boolean): Promise; /** * Clear the scan cache */ clearCache(): void; /** * Check if a file matches the scanner configuration * * @param filePath - File path to check * @returns True if file would be included in scan */ matchesFile(filePath: string): boolean; /** * Get files by type from last scan (requires prior scan) * * @param type - File type to filter by * @returns Files of the specified type, or empty array if no scan performed */ getFilesByType(type: RouteFileType): readonly DiscoveredFile[]; /** * Perform the actual scan operation */ private performScan; } /** * Create a new AutoScanner instance with configuration * * @param config - Scanner configuration * @returns Configured AutoScanner instance * * @example * ```typescript * const scanner = createAutoScanner({ * roots: ['src/routes'], * extensions: ['.tsx'], * ignore: ['**\/*.test.tsx'], * }); * ``` */ export declare function createAutoScanner(config?: Partial): AutoScanner; /** * Create a scanner with Next.js App Router conventions * * @param appDir - App directory path (default: 'src/app') * @returns Configured scanner for Next.js App Router */ export declare function createNextJsAppScanner(appDir?: string): AutoScanner; /** * Create a scanner with Remix conventions * * @param routesDir - Routes directory path (default: 'app/routes') * @returns Configured scanner for Remix */ export declare function createRemixScanner(routesDir?: string): AutoScanner; /** * Get the default AutoScanner instance * * @returns Default scanner instance */ export declare function getAutoScanner(): AutoScanner; /** * Reset the default scanner (useful for testing) */ export declare function resetAutoScanner(): void;