From 897d4cbfef954fc7c808c3bf92ce5066bbd3b3c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCne=C5=9F=20Bizim?= Date: Wed, 25 Feb 2026 01:04:49 +0300 Subject: [PATCH] feat(laravel): add Laravel framework path detection and entry point scoring MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add Laravel route/controller/job/listener/middleware/provider/policy/model path patterns with appropriate multipliers (1.5–3.0) - Add 'laravel' entry to FRAMEWORK_AST_PATTERNS for documentation - Add PHP ENTRY_POINT_PATTERNS: RESTful methods, __invoke, handle, boot, etc. - Add PHP/Laravel test file detection (Test.php, Spec.php, tests/feature/, tests/unit/) Co-Authored-By: Claude Sonnet 4.6 --- .../src/core/ingestion/entry-point-scoring.ts | 22 ++++++- .../src/core/ingestion/framework-detection.ts | 63 ++++++++++++++++++- .../src/core/ingestion/entry-point-scoring.ts | 22 ++++++- .../src/core/ingestion/framework-detection.ts | 61 ++++++++++++++++++ 4 files changed, 165 insertions(+), 3 deletions(-) diff --git a/gitnexus-web/src/core/ingestion/entry-point-scoring.ts b/gitnexus-web/src/core/ingestion/entry-point-scoring.ts index 1ef3d3ddc6..a9b589aac9 100644 --- a/gitnexus-web/src/core/ingestion/entry-point-scoring.ts +++ b/gitnexus-web/src/core/ingestion/entry-point-scoring.ts @@ -102,6 +102,21 @@ const ENTRY_POINT_PATTERNS: Record = { /^Run$/, // Run methods /^Start$/, // Start methods ], + + // PHP / Laravel + 'php': [ + /Controller$/, // UserController (class name convention) + /^handle$/, // Job::handle(), Listener::handle() + /^execute$/, // Command::execute() + /^boot$/, // ServiceProvider::boot() + /^register$/, // ServiceProvider::register() + /^__invoke$/, // Invokable controllers/actions + /^(index|show|store|update|destroy|create|edit)$/, // RESTful resource methods + /^(get|post|put|delete|patch)[A-Z]/, // Explicit HTTP method actions + /^run$/, // Command/Job run() + /^fire$/, // Event fire() + /^dispatch$/, // Dispatchable jobs + ], }; // ============================================================================ @@ -252,7 +267,12 @@ export function isTestFile(filePath: string): boolean { p.includes('/tests/') || // C# test patterns p.includes('.tests/') || - p.includes('tests.cs') + p.includes('tests.cs') || + // PHP/Laravel test patterns + p.endsWith('test.php') || + p.endsWith('spec.php') || + p.includes('/tests/feature/') || + p.includes('/tests/unit/') ); } diff --git a/gitnexus-web/src/core/ingestion/framework-detection.ts b/gitnexus-web/src/core/ingestion/framework-detection.ts index d3c75ab876..4e1b73d30b 100644 --- a/gitnexus-web/src/core/ingestion/framework-detection.ts +++ b/gitnexus-web/src/core/ingestion/framework-detection.ts @@ -195,8 +195,65 @@ export function detectFrameworkFromPath(filePath: string): FrameworkHint | null return { framework: 'c-cpp', entryPointMultiplier: 2.5, reason: 'c-app' }; } + // ========== PHP / LARAVEL FRAMEWORKS ========== + + // Laravel routes (highest - these ARE the entry point definitions) + if (p.includes('/routes/') && p.endsWith('.php')) { + return { framework: 'laravel', entryPointMultiplier: 3.0, reason: 'laravel-routes' }; + } + + // Laravel controllers (very high - receive HTTP requests) + if ((p.includes('/http/controllers/') || p.includes('/controllers/')) && p.endsWith('.php')) { + return { framework: 'laravel', entryPointMultiplier: 3.0, reason: 'laravel-controller' }; + } + + // Laravel controller by file name convention + if (p.endsWith('controller.php')) { + return { framework: 'laravel', entryPointMultiplier: 3.0, reason: 'laravel-controller-file' }; + } + + // Laravel console commands + if ((p.includes('/console/commands/') || p.includes('/commands/')) && p.endsWith('.php')) { + return { framework: 'laravel', entryPointMultiplier: 2.5, reason: 'laravel-command' }; + } + + // Laravel jobs (queue entry points) + if (p.includes('/jobs/') && p.endsWith('.php')) { + return { framework: 'laravel', entryPointMultiplier: 2.5, reason: 'laravel-job' }; + } + + // Laravel listeners (event-driven entry points) + if (p.includes('/listeners/') && p.endsWith('.php')) { + return { framework: 'laravel', entryPointMultiplier: 2.5, reason: 'laravel-listener' }; + } + + // Laravel middleware + if (p.includes('/http/middleware/') && p.endsWith('.php')) { + return { framework: 'laravel', entryPointMultiplier: 2.5, reason: 'laravel-middleware' }; + } + + // Laravel service providers + if (p.includes('/providers/') && p.endsWith('.php')) { + return { framework: 'laravel', entryPointMultiplier: 1.8, reason: 'laravel-provider' }; + } + + // Laravel policies + if (p.includes('/policies/') && p.endsWith('.php')) { + return { framework: 'laravel', entryPointMultiplier: 2.0, reason: 'laravel-policy' }; + } + + // Laravel models (important but not entry points per se) + if (p.includes('/models/') && p.endsWith('.php')) { + return { framework: 'laravel', entryPointMultiplier: 1.5, reason: 'laravel-model' }; + } + + // Generic PHP MVC: files ending with Controller.php + if (p.endsWith('controller.php')) { + return { framework: 'php-mvc', entryPointMultiplier: 2.5, reason: 'php-controller-file' }; + } + // ========== GENERIC PATTERNS ========== - + // Any language: index files in API folders if (p.includes('/api/') && ( p.endsWith('/index.ts') || p.endsWith('/index.js') || @@ -236,6 +293,10 @@ export const FRAMEWORK_AST_PATTERNS = { // Go patterns (function signatures) 'go-http': ['http.Handler', 'http.HandlerFunc', 'ServeHTTP'], + // PHP/Laravel + 'laravel': ['Route::get', 'Route::post', 'Route::put', 'Route::delete', + 'Route::resource', 'Route::apiResource', '#[Route('], + // Rust macros 'actix': ['#[get', '#[post', '#[put', '#[delete'], 'axum': ['Router::new'], diff --git a/gitnexus/src/core/ingestion/entry-point-scoring.ts b/gitnexus/src/core/ingestion/entry-point-scoring.ts index 55d0b1035f..ac8e9098d6 100644 --- a/gitnexus/src/core/ingestion/entry-point-scoring.ts +++ b/gitnexus/src/core/ingestion/entry-point-scoring.ts @@ -102,6 +102,21 @@ const ENTRY_POINT_PATTERNS: Record = { /^Run$/, // Run methods /^Start$/, // Start methods ], + + // PHP / Laravel + 'php': [ + /Controller$/, // UserController (class name convention) + /^handle$/, // Job::handle(), Listener::handle() + /^execute$/, // Command::execute() + /^boot$/, // ServiceProvider::boot() + /^register$/, // ServiceProvider::register() + /^__invoke$/, // Invokable controllers/actions + /^(index|show|store|update|destroy|create|edit)$/, // RESTful resource methods + /^(get|post|put|delete|patch)[A-Z]/, // Explicit HTTP method actions + /^run$/, // Command/Job run() + /^fire$/, // Event fire() + /^dispatch$/, // Dispatchable jobs + ], }; // ============================================================================ @@ -252,7 +267,12 @@ export function isTestFile(filePath: string): boolean { p.includes('/tests/') || // C# test patterns p.includes('.tests/') || - p.includes('tests.cs') + p.includes('tests.cs') || + // PHP/Laravel test patterns + p.endsWith('test.php') || + p.endsWith('spec.php') || + p.includes('/tests/feature/') || + p.includes('/tests/unit/') ); } diff --git a/gitnexus/src/core/ingestion/framework-detection.ts b/gitnexus/src/core/ingestion/framework-detection.ts index d3c75ab876..9296ec203f 100644 --- a/gitnexus/src/core/ingestion/framework-detection.ts +++ b/gitnexus/src/core/ingestion/framework-detection.ts @@ -195,6 +195,63 @@ export function detectFrameworkFromPath(filePath: string): FrameworkHint | null return { framework: 'c-cpp', entryPointMultiplier: 2.5, reason: 'c-app' }; } + // ========== PHP / LARAVEL FRAMEWORKS ========== + + // Laravel routes (highest - these ARE the entry point definitions) + if (p.includes('/routes/') && p.endsWith('.php')) { + return { framework: 'laravel', entryPointMultiplier: 3.0, reason: 'laravel-routes' }; + } + + // Laravel controllers (very high - receive HTTP requests) + if ((p.includes('/http/controllers/') || p.includes('/controllers/')) && p.endsWith('.php')) { + return { framework: 'laravel', entryPointMultiplier: 3.0, reason: 'laravel-controller' }; + } + + // Laravel controller by file name convention + if (p.endsWith('controller.php')) { + return { framework: 'laravel', entryPointMultiplier: 3.0, reason: 'laravel-controller-file' }; + } + + // Laravel console commands + if ((p.includes('/console/commands/') || p.includes('/commands/')) && p.endsWith('.php')) { + return { framework: 'laravel', entryPointMultiplier: 2.5, reason: 'laravel-command' }; + } + + // Laravel jobs (queue entry points) + if (p.includes('/jobs/') && p.endsWith('.php')) { + return { framework: 'laravel', entryPointMultiplier: 2.5, reason: 'laravel-job' }; + } + + // Laravel listeners (event-driven entry points) + if (p.includes('/listeners/') && p.endsWith('.php')) { + return { framework: 'laravel', entryPointMultiplier: 2.5, reason: 'laravel-listener' }; + } + + // Laravel middleware + if (p.includes('/http/middleware/') && p.endsWith('.php')) { + return { framework: 'laravel', entryPointMultiplier: 2.5, reason: 'laravel-middleware' }; + } + + // Laravel service providers + if (p.includes('/providers/') && p.endsWith('.php')) { + return { framework: 'laravel', entryPointMultiplier: 1.8, reason: 'laravel-provider' }; + } + + // Laravel policies + if (p.includes('/policies/') && p.endsWith('.php')) { + return { framework: 'laravel', entryPointMultiplier: 2.0, reason: 'laravel-policy' }; + } + + // Laravel models (important but not entry points per se) + if (p.includes('/models/') && p.endsWith('.php')) { + return { framework: 'laravel', entryPointMultiplier: 1.5, reason: 'laravel-model' }; + } + + // Generic PHP MVC: files ending with Controller.php + if (p.endsWith('controller.php')) { + return { framework: 'php-mvc', entryPointMultiplier: 2.5, reason: 'php-controller-file' }; + } + // ========== GENERIC PATTERNS ========== // Any language: index files in API folders @@ -236,6 +293,10 @@ export const FRAMEWORK_AST_PATTERNS = { // Go patterns (function signatures) 'go-http': ['http.Handler', 'http.HandlerFunc', 'ServeHTTP'], + // PHP/Laravel + 'laravel': ['Route::get', 'Route::post', 'Route::put', 'Route::delete', + 'Route::resource', 'Route::apiResource', '#[Route('], + // Rust macros 'actix': ['#[get', '#[post', '#[put', '#[delete'], 'axum': ['Router::new'],