mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-10-05 02:43:32 +00:00
refactor(ingestion): consolidate per-language patterns into LanguageProvider
Move entry-point name patterns and AST framework detection patterns from shared maps in entry-point-scoring.ts and framework-detection.ts into each LanguageProvider. The shared files now build their lookup tables dynamically from the provider registry at module load. This aligns with the architecture principle that shared pipeline code must not name languages. Adding a new language no longer requires modifying entry-point-scoring.ts or framework-detection.ts — the provider file is the single source of truth for all language-specific data. New LanguageProvider fields: - entryPointPatterns: RegExp[] (default: []) - astFrameworkPatterns: AstFrameworkPatternConfig[] (default: [])
This commit is contained in:
parent
26b39560ce
commit
0b84496cfd
18 changed files with 538 additions and 599 deletions
|
|
@ -12,18 +12,15 @@
|
|||
|
||||
import { detectFrameworkFromPath } from './framework-detection.js';
|
||||
import { SupportedLanguages } from 'gitnexus-shared';
|
||||
import { providers } from './languages/index.js';
|
||||
|
||||
// ============================================================================
|
||||
// NAME PATTERNS - All 13 supported languages
|
||||
// NAME PATTERNS
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Common entry point naming patterns by language.
|
||||
* These patterns indicate functions that are likely feature entry points.
|
||||
*
|
||||
* Universal patterns are separated from per-language patterns so the per-language
|
||||
* table can use `satisfies Record<SupportedLanguages, RegExp[]>` for compile-time
|
||||
* exhaustiveness — the compiler catches any missing language entry.
|
||||
* Universal entry point naming patterns shared across all languages.
|
||||
* Per-language patterns live on each LanguageProvider.entryPointPatterns.
|
||||
*/
|
||||
const UNIVERSAL_ENTRY_POINT_PATTERNS: RegExp[] = [
|
||||
/^(main|init|bootstrap|start|run|setup|configure)$/i,
|
||||
|
|
@ -40,201 +37,11 @@ const UNIVERSAL_ENTRY_POINT_PATTERNS: RegExp[] = [
|
|||
/^emit[A-Z]/, // emitEvent
|
||||
];
|
||||
|
||||
export const ENTRY_POINT_PATTERNS = {
|
||||
// JavaScript/TypeScript
|
||||
[SupportedLanguages.JavaScript]: [
|
||||
/^use[A-Z]/, // React hooks (useEffect, etc.)
|
||||
],
|
||||
[SupportedLanguages.TypeScript]: [
|
||||
/^use[A-Z]/, // React hooks
|
||||
],
|
||||
|
||||
// Python
|
||||
[SupportedLanguages.Python]: [
|
||||
/^app$/, // Flask/FastAPI app
|
||||
/^(get|post|put|delete|patch)_/i, // REST conventions
|
||||
/^api_/, // API functions
|
||||
/^view_/, // Django views
|
||||
],
|
||||
|
||||
// Java
|
||||
[SupportedLanguages.Java]: [
|
||||
/^do[A-Z]/, // doGet, doPost (Servlets)
|
||||
/^create[A-Z]/, // Factory patterns
|
||||
/^build[A-Z]/, // Builder patterns
|
||||
/Service$/, // UserService
|
||||
],
|
||||
|
||||
// Kotlin
|
||||
[SupportedLanguages.Kotlin]: [
|
||||
/^on(Create|Start|Resume|Pause|Stop|Destroy)$/, // Android lifecycle
|
||||
/^do[A-Z]/, // doGet, doPost (shared JVM Servlet pattern)
|
||||
/^create[A-Z]/, // Factory patterns
|
||||
/^build[A-Z]/, // Builder patterns
|
||||
/ViewModel$/, // MVVM pattern (Android)
|
||||
/^module$/, // Ktor module entry point
|
||||
/Service$/, // Service classes
|
||||
],
|
||||
|
||||
// C#
|
||||
[SupportedLanguages.CSharp]: [
|
||||
/^(Get|Post|Put|Delete|Patch)/, // ASP.NET action methods
|
||||
/Action$/, // MVC actions
|
||||
/^On[A-Z]/, // Event handlers / Blazor lifecycle
|
||||
/Async$/, // Async entry points
|
||||
/^Configure$/, // Startup.Configure
|
||||
/^ConfigureServices$/, // Startup.ConfigureServices
|
||||
/^Handle$/, // MediatR / generic handler
|
||||
/^Execute$/, // Command pattern
|
||||
/^Invoke$/, // Middleware Invoke
|
||||
/^Map[A-Z]/, // Minimal API MapGet, MapPost
|
||||
/Service$/, // Service classes
|
||||
/^Seed/, // Database seeding
|
||||
],
|
||||
|
||||
// Go
|
||||
[SupportedLanguages.Go]: [
|
||||
/Handler$/, // http.Handler pattern
|
||||
/^Serve/, // ServeHTTP
|
||||
/^New[A-Z]/, // Constructor pattern (returns new instance)
|
||||
/^Make[A-Z]/, // Make functions
|
||||
],
|
||||
|
||||
// Rust
|
||||
[SupportedLanguages.Rust]: [
|
||||
/^(get|post|put|delete)_handler$/i,
|
||||
/^handle_/, // handle_request
|
||||
/^new$/, // Constructor pattern
|
||||
/^run$/, // run entry point
|
||||
/^spawn/, // Async spawn
|
||||
],
|
||||
|
||||
// C - explicit main() boost plus common C entry point conventions
|
||||
[SupportedLanguages.C]: [
|
||||
/^main$/, // THE entry point
|
||||
/^init_/, // init_server, init_client
|
||||
/_init$/, // module_init, server_init
|
||||
/^start_/, // start_server
|
||||
/_start$/, // thread_start
|
||||
/^run_/, // run_loop
|
||||
/_run$/, // event_run
|
||||
/^stop_/, // stop_server
|
||||
/_stop$/, // service_stop
|
||||
/^open_/, // open_connection
|
||||
/_open$/, // file_open
|
||||
/^close_/, // close_connection
|
||||
/_close$/, // socket_close
|
||||
/^create_/, // create_session
|
||||
/_create$/, // object_create
|
||||
/^destroy_/, // destroy_session
|
||||
/_destroy$/, // object_destroy
|
||||
/^handle_/, // handle_request
|
||||
/_handler$/, // signal_handler
|
||||
/_callback$/, // event_callback
|
||||
/^cmd_/, // tmux: cmd_new_window, cmd_attach_session
|
||||
/^server_/, // server_start, server_loop
|
||||
/^client_/, // client_connect
|
||||
/^session_/, // session_create
|
||||
/^window_/, // window_resize (tmux)
|
||||
/^key_/, // key_press
|
||||
/^input_/, // input_parse
|
||||
/^output_/, // output_write
|
||||
/^notify_/, // notify_client
|
||||
/^control_/, // control_start
|
||||
],
|
||||
|
||||
// C++ - same as C plus OOP/template patterns
|
||||
[SupportedLanguages.CPlusPlus]: [
|
||||
/^main$/, // THE entry point
|
||||
/^init_/,
|
||||
/_init$/,
|
||||
/^Create[A-Z]/, // Factory patterns
|
||||
/^create_/,
|
||||
/^Run$/, // Run methods
|
||||
/^run$/,
|
||||
/^Start$/, // Start methods
|
||||
/^start$/,
|
||||
/^handle_/,
|
||||
/_handler$/,
|
||||
/_callback$/,
|
||||
/^OnEvent/, // Event callbacks
|
||||
/^on_/,
|
||||
/::Run$/, // Class::Run
|
||||
/::Start$/, // Class::Start
|
||||
/::Init$/, // Class::Init
|
||||
/::Execute$/, // Class::Execute
|
||||
],
|
||||
|
||||
// Swift / iOS
|
||||
[SupportedLanguages.Swift]: [
|
||||
/^viewDidLoad$/, // UIKit lifecycle
|
||||
/^viewWillAppear$/, // UIKit lifecycle
|
||||
/^viewDidAppear$/, // UIKit lifecycle
|
||||
/^viewWillDisappear$/, // UIKit lifecycle
|
||||
/^viewDidDisappear$/, // UIKit lifecycle
|
||||
/^application\(/, // AppDelegate methods
|
||||
/^scene\(/, // SceneDelegate methods
|
||||
/^body$/, // SwiftUI View.body
|
||||
/Coordinator$/, // Coordinator pattern
|
||||
/^sceneDidBecomeActive$/, // SceneDelegate lifecycle
|
||||
/^sceneWillResignActive$/, // SceneDelegate lifecycle
|
||||
/^didFinishLaunchingWithOptions$/, // AppDelegate
|
||||
/ViewController$/, // ViewController classes
|
||||
/^configure[A-Z]/, // Configuration methods
|
||||
/^setup[A-Z]/, // Setup methods
|
||||
/^makeBody$/, // SwiftUI ViewModifier
|
||||
],
|
||||
|
||||
// PHP / Laravel
|
||||
[SupportedLanguages.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
|
||||
/Service$/, // UserService (Service layer)
|
||||
/Repository$/, // UserRepository (Repository pattern)
|
||||
/^find$/, // Repository::find()
|
||||
/^findAll$/, // Repository::findAll()
|
||||
/^save$/, // Repository::save()
|
||||
/^delete$/, // Repository::delete()
|
||||
],
|
||||
|
||||
// Ruby
|
||||
[SupportedLanguages.Ruby]: [
|
||||
/^call$/, // Service objects (MyService.call)
|
||||
/^perform$/, // Background jobs (Sidekiq, ActiveJob)
|
||||
/^execute$/, // Command pattern
|
||||
],
|
||||
|
||||
// Dart / Flutter
|
||||
[SupportedLanguages.Dart]: [
|
||||
/^main$/, // App entry
|
||||
/^build$/, // Widget.build — fundamental Flutter render entry point
|
||||
/^createState$/, // StatefulWidget.createState
|
||||
/^initState$/, // State lifecycle initialization
|
||||
/^dispose$/, // State lifecycle teardown
|
||||
/^didChangeDependencies$/, // State lifecycle — InheritedWidget changes
|
||||
/^didUpdateWidget$/, // State lifecycle — widget rebuild with new config
|
||||
/^runApp$/, // App entry point
|
||||
/^onEvent$/, // BLoC event handler
|
||||
/^mapEventToState$/, // Legacy BLoC pattern
|
||||
],
|
||||
[SupportedLanguages.Vue]: [], // Vue uses TypeScript queries — entry points handled via TS patterns
|
||||
[SupportedLanguages.Cobol]: [], // Standalone regex processor — no tree-sitter entry points
|
||||
} satisfies Record<SupportedLanguages, RegExp[]>;
|
||||
|
||||
/** Pre-computed merged patterns (universal + language-specific) to avoid per-call array allocation. */
|
||||
/** Pre-computed merged patterns (universal + language-specific) from providers. */
|
||||
const MERGED_ENTRY_POINT_PATTERNS = Object.fromEntries(
|
||||
Object.values(SupportedLanguages).map((lang) => [
|
||||
Object.entries(providers).map(([lang, provider]) => [
|
||||
lang,
|
||||
[...UNIVERSAL_ENTRY_POINT_PATTERNS, ...(ENTRY_POINT_PATTERNS[lang] ?? [])],
|
||||
[...UNIVERSAL_ENTRY_POINT_PATTERNS, ...(provider.entryPointPatterns ?? [])],
|
||||
]),
|
||||
) as Record<SupportedLanguages, RegExp[]>;
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@
|
|||
*/
|
||||
|
||||
import { SupportedLanguages } from 'gitnexus-shared';
|
||||
import type { AstFrameworkPatternConfig } from './language-provider.js';
|
||||
import { providers } from './languages/index.js';
|
||||
|
||||
// ============================================================================
|
||||
// TYPES
|
||||
|
|
@ -518,395 +520,14 @@ export function detectFrameworkFromPath(filePath: string): FrameworkHint | null
|
|||
// AST-BASED FRAMEWORK DETECTION
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Patterns that indicate framework entry points within code definitions.
|
||||
* These are matched against AST node text (class/method/function declaration text).
|
||||
*/
|
||||
export const FRAMEWORK_AST_PATTERNS = {
|
||||
// JavaScript/TypeScript decorators
|
||||
nestjs: ['@Controller', '@Get', '@Post', '@Put', '@Delete', '@Patch'],
|
||||
'expo-router': [
|
||||
'router.push',
|
||||
'router.replace',
|
||||
'router.navigate',
|
||||
'useRouter',
|
||||
'useLocalSearchParams',
|
||||
'useSegments',
|
||||
'expo-router',
|
||||
],
|
||||
express: ['app.get', 'app.post', 'app.put', 'app.delete', 'router.get', 'router.post'],
|
||||
|
||||
// Python decorators
|
||||
fastapi: ['@app.get', '@app.post', '@app.put', '@app.delete', '@router.get'],
|
||||
flask: ['@app.route', '@blueprint.route'],
|
||||
|
||||
// Java annotations
|
||||
spring: ['@RestController', '@Controller', '@GetMapping', '@PostMapping', '@RequestMapping'],
|
||||
jaxrs: ['@Path', '@GET', '@POST', '@PUT', '@DELETE'],
|
||||
|
||||
// C# attributes
|
||||
aspnet: [
|
||||
'[ApiController]',
|
||||
'[HttpGet]',
|
||||
'[HttpPost]',
|
||||
'[HttpPut]',
|
||||
'[HttpDelete]',
|
||||
'[Route]',
|
||||
'[Authorize]',
|
||||
'[AllowAnonymous]',
|
||||
],
|
||||
signalr: ['[HubMethodName]', ': Hub', ': Hub<'],
|
||||
blazor: ['@page', '[Parameter]', '@inject'],
|
||||
efcore: ['DbContext', 'DbSet<', 'OnModelCreating'],
|
||||
|
||||
// Go patterns (function signatures include framework types)
|
||||
'go-http': [
|
||||
'http.Handler',
|
||||
'http.HandlerFunc',
|
||||
'ServeHTTP',
|
||||
'http.ResponseWriter',
|
||||
'http.Request',
|
||||
],
|
||||
gin: ['gin.Context', 'gin.Default', 'gin.New'],
|
||||
echo: ['echo.Context', 'echo.New'],
|
||||
fiber: ['fiber.Ctx', 'fiber.New', 'fiber.App'],
|
||||
'go-grpc': ['grpc.Server', 'RegisterServer', 'pb.Unimplemented'],
|
||||
|
||||
// ORM patterns
|
||||
prisma: ['prisma.', 'PrismaClient', '@prisma/client'],
|
||||
supabase: ['supabase.from', 'createClient', '@supabase/supabase-js'],
|
||||
|
||||
// PHP/Laravel
|
||||
laravel: [
|
||||
'Route::get',
|
||||
'Route::post',
|
||||
'Route::put',
|
||||
'Route::delete',
|
||||
'Route::resource',
|
||||
'Route::apiResource',
|
||||
'#[Route(',
|
||||
],
|
||||
|
||||
// Rust macros (proc-macro attributes in definition text)
|
||||
actix: ['#[get', '#[post', '#[put', '#[delete', '#[actix_web', 'HttpRequest', 'HttpResponse'],
|
||||
axum: ['Router::new', 'axum::extract', 'axum::routing'],
|
||||
rocket: ['#[get', '#[post', '#[launch', 'rocket::'],
|
||||
tokio: ['#[tokio::main]', '#[tokio::test]'],
|
||||
|
||||
// C++ patterns (Qt, Boost)
|
||||
qt: [
|
||||
'Q_OBJECT',
|
||||
'Q_INVOKABLE',
|
||||
'Q_PROPERTY',
|
||||
'Q_SIGNALS',
|
||||
'Q_SLOTS',
|
||||
'Q_SIGNAL',
|
||||
'Q_SLOT',
|
||||
'QWidget',
|
||||
'QApplication',
|
||||
],
|
||||
|
||||
// Swift/iOS
|
||||
uikit: [
|
||||
'viewDidLoad',
|
||||
'viewWillAppear',
|
||||
'viewDidAppear',
|
||||
'UIViewController',
|
||||
'@IBOutlet',
|
||||
'@IBAction',
|
||||
'@objc',
|
||||
],
|
||||
swiftui: [
|
||||
'@main',
|
||||
'WindowGroup',
|
||||
'ContentView',
|
||||
'@StateObject',
|
||||
'@ObservedObject',
|
||||
'@EnvironmentObject',
|
||||
'@Published',
|
||||
],
|
||||
vapor: ['app.get', 'app.post', 'req.content.decode', 'Vapor'],
|
||||
|
||||
// Ruby patterns (class-level macros in definition text)
|
||||
rails: [
|
||||
'ApplicationController',
|
||||
'ApplicationRecord',
|
||||
'ActiveRecord::Base',
|
||||
'before_action',
|
||||
'after_action',
|
||||
'has_many',
|
||||
'belongs_to',
|
||||
'has_one',
|
||||
'validates',
|
||||
],
|
||||
sinatra: ['Sinatra::Base', 'Sinatra::Application'],
|
||||
|
||||
// Dart/Flutter
|
||||
flutter: [
|
||||
'StatelessWidget',
|
||||
'StatefulWidget',
|
||||
'BuildContext',
|
||||
'Widget build',
|
||||
'ChangeNotifier',
|
||||
'GetxController',
|
||||
'Cubit<',
|
||||
'Bloc<',
|
||||
'ConsumerWidget',
|
||||
],
|
||||
riverpod: ['@riverpod', 'ref.watch', 'ref.read', 'AsyncNotifier', 'Notifier'],
|
||||
};
|
||||
|
||||
interface AstFrameworkPatternConfig {
|
||||
framework: string;
|
||||
entryPointMultiplier: number;
|
||||
reason: string;
|
||||
patterns: string[];
|
||||
}
|
||||
|
||||
export const AST_FRAMEWORK_PATTERNS_BY_LANGUAGE = {
|
||||
[SupportedLanguages.JavaScript]: [
|
||||
{
|
||||
framework: 'nestjs',
|
||||
entryPointMultiplier: 3.2,
|
||||
reason: 'nestjs-decorator',
|
||||
patterns: FRAMEWORK_AST_PATTERNS.nestjs,
|
||||
},
|
||||
{
|
||||
framework: 'expo-router',
|
||||
entryPointMultiplier: 2.5,
|
||||
reason: 'expo-router-navigation',
|
||||
patterns: FRAMEWORK_AST_PATTERNS['expo-router'],
|
||||
},
|
||||
],
|
||||
[SupportedLanguages.TypeScript]: [
|
||||
{
|
||||
framework: 'nestjs',
|
||||
entryPointMultiplier: 3.2,
|
||||
reason: 'nestjs-decorator',
|
||||
patterns: FRAMEWORK_AST_PATTERNS.nestjs,
|
||||
},
|
||||
{
|
||||
framework: 'expo-router',
|
||||
entryPointMultiplier: 2.5,
|
||||
reason: 'expo-router-navigation',
|
||||
patterns: FRAMEWORK_AST_PATTERNS['expo-router'],
|
||||
},
|
||||
],
|
||||
[SupportedLanguages.Python]: [
|
||||
{
|
||||
framework: 'fastapi',
|
||||
entryPointMultiplier: 3.0,
|
||||
reason: 'fastapi-decorator',
|
||||
patterns: FRAMEWORK_AST_PATTERNS.fastapi,
|
||||
},
|
||||
{
|
||||
framework: 'flask',
|
||||
entryPointMultiplier: 2.8,
|
||||
reason: 'flask-decorator',
|
||||
patterns: FRAMEWORK_AST_PATTERNS.flask,
|
||||
},
|
||||
],
|
||||
[SupportedLanguages.Java]: [
|
||||
{
|
||||
framework: 'spring',
|
||||
entryPointMultiplier: 3.2,
|
||||
reason: 'spring-annotation',
|
||||
patterns: FRAMEWORK_AST_PATTERNS.spring,
|
||||
},
|
||||
{
|
||||
framework: 'jaxrs',
|
||||
entryPointMultiplier: 3.0,
|
||||
reason: 'jaxrs-annotation',
|
||||
patterns: FRAMEWORK_AST_PATTERNS.jaxrs,
|
||||
},
|
||||
],
|
||||
[SupportedLanguages.Kotlin]: [
|
||||
{
|
||||
framework: 'spring-kotlin',
|
||||
entryPointMultiplier: 3.2,
|
||||
reason: 'spring-kotlin-annotation',
|
||||
patterns: FRAMEWORK_AST_PATTERNS.spring,
|
||||
},
|
||||
{
|
||||
framework: 'jaxrs',
|
||||
entryPointMultiplier: 3.0,
|
||||
reason: 'jaxrs-annotation',
|
||||
patterns: FRAMEWORK_AST_PATTERNS.jaxrs,
|
||||
},
|
||||
{
|
||||
framework: 'ktor',
|
||||
entryPointMultiplier: 2.8,
|
||||
reason: 'ktor-routing',
|
||||
patterns: ['routing', 'embeddedServer', 'Application.module'],
|
||||
},
|
||||
{
|
||||
framework: 'android-kotlin',
|
||||
entryPointMultiplier: 2.5,
|
||||
reason: 'android-annotation',
|
||||
patterns: ['@AndroidEntryPoint', 'AppCompatActivity', 'Fragment('],
|
||||
},
|
||||
],
|
||||
[SupportedLanguages.CSharp]: [
|
||||
{
|
||||
framework: 'aspnet',
|
||||
entryPointMultiplier: 3.2,
|
||||
reason: 'aspnet-attribute',
|
||||
patterns: FRAMEWORK_AST_PATTERNS.aspnet,
|
||||
},
|
||||
{
|
||||
framework: 'signalr',
|
||||
entryPointMultiplier: 2.8,
|
||||
reason: 'signalr-attribute',
|
||||
patterns: FRAMEWORK_AST_PATTERNS.signalr,
|
||||
},
|
||||
{
|
||||
framework: 'blazor',
|
||||
entryPointMultiplier: 2.5,
|
||||
reason: 'blazor-attribute',
|
||||
patterns: FRAMEWORK_AST_PATTERNS.blazor,
|
||||
},
|
||||
{
|
||||
framework: 'efcore',
|
||||
entryPointMultiplier: 2.0,
|
||||
reason: 'efcore-pattern',
|
||||
patterns: FRAMEWORK_AST_PATTERNS.efcore,
|
||||
},
|
||||
],
|
||||
[SupportedLanguages.PHP]: [
|
||||
{
|
||||
framework: 'laravel',
|
||||
entryPointMultiplier: 3.0,
|
||||
reason: 'php-route-attribute',
|
||||
patterns: FRAMEWORK_AST_PATTERNS.laravel,
|
||||
},
|
||||
],
|
||||
[SupportedLanguages.Go]: [
|
||||
{
|
||||
framework: 'go-http',
|
||||
entryPointMultiplier: 2.5,
|
||||
reason: 'go-http-handler',
|
||||
patterns: FRAMEWORK_AST_PATTERNS['go-http'],
|
||||
},
|
||||
{
|
||||
framework: 'gin',
|
||||
entryPointMultiplier: 3.0,
|
||||
reason: 'gin-handler',
|
||||
patterns: FRAMEWORK_AST_PATTERNS.gin,
|
||||
},
|
||||
{
|
||||
framework: 'echo',
|
||||
entryPointMultiplier: 3.0,
|
||||
reason: 'echo-handler',
|
||||
patterns: FRAMEWORK_AST_PATTERNS.echo,
|
||||
},
|
||||
{
|
||||
framework: 'fiber',
|
||||
entryPointMultiplier: 3.0,
|
||||
reason: 'fiber-handler',
|
||||
patterns: FRAMEWORK_AST_PATTERNS.fiber,
|
||||
},
|
||||
{
|
||||
framework: 'go-grpc',
|
||||
entryPointMultiplier: 2.8,
|
||||
reason: 'grpc-service',
|
||||
patterns: FRAMEWORK_AST_PATTERNS['go-grpc'],
|
||||
},
|
||||
],
|
||||
[SupportedLanguages.Rust]: [
|
||||
{
|
||||
framework: 'actix-web',
|
||||
entryPointMultiplier: 3.0,
|
||||
reason: 'actix-attribute',
|
||||
patterns: FRAMEWORK_AST_PATTERNS.actix,
|
||||
},
|
||||
{
|
||||
framework: 'axum',
|
||||
entryPointMultiplier: 3.0,
|
||||
reason: 'axum-routing',
|
||||
patterns: FRAMEWORK_AST_PATTERNS.axum,
|
||||
},
|
||||
{
|
||||
framework: 'rocket',
|
||||
entryPointMultiplier: 3.0,
|
||||
reason: 'rocket-attribute',
|
||||
patterns: FRAMEWORK_AST_PATTERNS.rocket,
|
||||
},
|
||||
{
|
||||
framework: 'tokio',
|
||||
entryPointMultiplier: 2.5,
|
||||
reason: 'tokio-runtime',
|
||||
patterns: FRAMEWORK_AST_PATTERNS.tokio,
|
||||
},
|
||||
],
|
||||
[SupportedLanguages.C]: [], // C has no framework-specific AST patterns (POSIX/socket patterns are in entry-point-scoring)
|
||||
[SupportedLanguages.CPlusPlus]: [
|
||||
{
|
||||
framework: 'qt',
|
||||
entryPointMultiplier: 2.8,
|
||||
reason: 'qt-macro',
|
||||
patterns: FRAMEWORK_AST_PATTERNS.qt,
|
||||
},
|
||||
],
|
||||
[SupportedLanguages.Swift]: [
|
||||
{
|
||||
framework: 'uikit',
|
||||
entryPointMultiplier: 2.5,
|
||||
reason: 'uikit-lifecycle',
|
||||
patterns: FRAMEWORK_AST_PATTERNS.uikit,
|
||||
},
|
||||
{
|
||||
framework: 'swiftui',
|
||||
entryPointMultiplier: 2.8,
|
||||
reason: 'swiftui-pattern',
|
||||
patterns: FRAMEWORK_AST_PATTERNS.swiftui,
|
||||
},
|
||||
{
|
||||
framework: 'vapor',
|
||||
entryPointMultiplier: 3.0,
|
||||
reason: 'vapor-routing',
|
||||
patterns: FRAMEWORK_AST_PATTERNS.vapor,
|
||||
},
|
||||
],
|
||||
[SupportedLanguages.Ruby]: [
|
||||
{
|
||||
framework: 'rails',
|
||||
entryPointMultiplier: 3.0,
|
||||
reason: 'rails-pattern',
|
||||
patterns: FRAMEWORK_AST_PATTERNS.rails,
|
||||
},
|
||||
{
|
||||
framework: 'sinatra',
|
||||
entryPointMultiplier: 2.8,
|
||||
reason: 'sinatra-pattern',
|
||||
patterns: FRAMEWORK_AST_PATTERNS.sinatra,
|
||||
},
|
||||
],
|
||||
[SupportedLanguages.Dart]: [
|
||||
{
|
||||
framework: 'flutter',
|
||||
entryPointMultiplier: 2.5,
|
||||
reason: 'flutter-widget',
|
||||
patterns: FRAMEWORK_AST_PATTERNS.flutter,
|
||||
},
|
||||
{
|
||||
framework: 'riverpod',
|
||||
entryPointMultiplier: 2.8,
|
||||
reason: 'riverpod-pattern',
|
||||
patterns: FRAMEWORK_AST_PATTERNS.riverpod,
|
||||
},
|
||||
],
|
||||
[SupportedLanguages.Vue]: [], // Vue uses TypeScript AST framework detection
|
||||
[SupportedLanguages.Cobol]: [], // Standalone regex processor — no AST framework patterns
|
||||
} satisfies Record<SupportedLanguages, AstFrameworkPatternConfig[]>;
|
||||
|
||||
/** Pre-lowercased patterns for O(1) pattern matching at runtime */
|
||||
const AST_PATTERNS_LOWERED: Record<
|
||||
string,
|
||||
Array<{ framework: string; entryPointMultiplier: number; reason: string; patterns: string[] }>
|
||||
> = Object.fromEntries(
|
||||
Object.entries(AST_FRAMEWORK_PATTERNS_BY_LANGUAGE).map(([lang, cfgs]) => [
|
||||
/** Pre-lowercased patterns for O(1) pattern matching at runtime — built from providers. */
|
||||
const AST_PATTERNS_LOWERED: Record<string, AstFrameworkPatternConfig[]> = Object.fromEntries(
|
||||
Object.entries(providers).map(([lang, provider]) => [
|
||||
lang,
|
||||
cfgs.map((cfg) => ({ ...cfg, patterns: cfg.patterns.map((p) => p.toLowerCase()) })),
|
||||
(provider.astFrameworkPatterns ?? []).map((cfg) => ({
|
||||
...cfg,
|
||||
patterns: cfg.patterns.map((p) => p.toLowerCase()),
|
||||
})),
|
||||
]),
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -78,6 +78,14 @@ export type ImportSemantics =
|
|||
| 'namespace'
|
||||
| 'explicit-reexport';
|
||||
|
||||
/** Configuration for AST-based framework detection patterns. */
|
||||
export interface AstFrameworkPatternConfig {
|
||||
framework: string;
|
||||
entryPointMultiplier: number;
|
||||
reason: string;
|
||||
patterns: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Everything a language needs to provide.
|
||||
* Required fields must be explicitly set; optional fields have defaults
|
||||
|
|
@ -89,6 +97,16 @@ interface LanguageProviderConfig {
|
|||
/** File extensions that map to this language (e.g., ['.ts', '.tsx']) */
|
||||
readonly extensions: readonly string[];
|
||||
|
||||
/** Entry-point function name patterns specific to this language.
|
||||
* Merged with universal patterns at runtime for process detection scoring.
|
||||
* Default: [] (only universal patterns apply). */
|
||||
readonly entryPointPatterns?: readonly RegExp[];
|
||||
|
||||
/** AST-based framework detection patterns for this language.
|
||||
* Used by detectFrameworkFromAST to identify framework entry points.
|
||||
* Default: [] (no AST framework detection for this language). */
|
||||
readonly astFrameworkPatterns?: readonly AstFrameworkPatternConfig[];
|
||||
|
||||
// ── Parser ────────────────────────────────────────────────────────
|
||||
/** Parse strategy: 'tree-sitter' (default) uses AST parsing via tree-sitter.
|
||||
* 'standalone' means the language has its own regex-based processor and
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import { SupportedLanguages } from 'gitnexus-shared';
|
|||
import { createClassExtractor } from '../class-extractors/generic.js';
|
||||
import { cClassConfig, cppClassConfig } from '../class-extractors/configs/c-cpp.js';
|
||||
import { defineLanguage } from '../language-provider.js';
|
||||
import type { AstFrameworkPatternConfig } from '../language-provider.js';
|
||||
import { typeConfig as cCppConfig } from '../type-extractors/c-cpp.js';
|
||||
import { cCppExportChecker } from '../export-detection.js';
|
||||
import { createImportResolver } from '../import-resolvers/resolver-factory.js';
|
||||
|
|
@ -317,6 +318,38 @@ const cppLabelOverride: NonNullable<LanguageProvider['labelOverride']> = (
|
|||
export const cProvider = defineLanguage({
|
||||
id: SupportedLanguages.C,
|
||||
extensions: ['.c'],
|
||||
entryPointPatterns: [
|
||||
/^main$/,
|
||||
/^init_/,
|
||||
/_init$/,
|
||||
/^start_/,
|
||||
/_start$/,
|
||||
/^run_/,
|
||||
/_run$/,
|
||||
/^stop_/,
|
||||
/_stop$/,
|
||||
/^open_/,
|
||||
/_open$/,
|
||||
/^close_/,
|
||||
/_close$/,
|
||||
/^create_/,
|
||||
/_create$/,
|
||||
/^destroy_/,
|
||||
/_destroy$/,
|
||||
/^handle_/,
|
||||
/_handler$/,
|
||||
/_callback$/,
|
||||
/^cmd_/,
|
||||
/^server_/,
|
||||
/^client_/,
|
||||
/^session_/,
|
||||
/^window_/,
|
||||
/^key_/,
|
||||
/^input_/,
|
||||
/^output_/,
|
||||
/^notify_/,
|
||||
/^control_/,
|
||||
],
|
||||
treeSitterQueries: C_QUERIES,
|
||||
typeConfig: cCppConfig,
|
||||
exportChecker: cCppExportChecker,
|
||||
|
|
@ -338,6 +371,44 @@ export const cProvider = defineLanguage({
|
|||
export const cppProvider = defineLanguage({
|
||||
id: SupportedLanguages.CPlusPlus,
|
||||
extensions: ['.cpp', '.cc', '.cxx', '.h', '.hpp', '.hxx', '.hh'],
|
||||
entryPointPatterns: [
|
||||
/^main$/,
|
||||
/^init_/,
|
||||
/_init$/,
|
||||
/^Create[A-Z]/,
|
||||
/^create_/,
|
||||
/^Run$/,
|
||||
/^run$/,
|
||||
/^Start$/,
|
||||
/^start$/,
|
||||
/^handle_/,
|
||||
/_handler$/,
|
||||
/_callback$/,
|
||||
/^OnEvent/,
|
||||
/^on_/,
|
||||
/::Run$/,
|
||||
/::Start$/,
|
||||
/::Init$/,
|
||||
/::Execute$/,
|
||||
],
|
||||
astFrameworkPatterns: [
|
||||
{
|
||||
framework: 'qt',
|
||||
entryPointMultiplier: 2.8,
|
||||
reason: 'qt-macro',
|
||||
patterns: [
|
||||
'Q_OBJECT',
|
||||
'Q_INVOKABLE',
|
||||
'Q_PROPERTY',
|
||||
'Q_SIGNALS',
|
||||
'Q_SLOTS',
|
||||
'Q_SIGNAL',
|
||||
'Q_SLOT',
|
||||
'QWidget',
|
||||
'QApplication',
|
||||
],
|
||||
},
|
||||
],
|
||||
treeSitterQueries: CPP_QUERIES,
|
||||
typeConfig: cCppConfig,
|
||||
exportChecker: cCppExportChecker,
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ export const cobolProvider = defineLanguage({
|
|||
id: SupportedLanguages.Cobol,
|
||||
parseStrategy: 'standalone',
|
||||
extensions: [], // COBOL files detected by cobol-processor's isCobolFile/isJclFile
|
||||
entryPointPatterns: [],
|
||||
astFrameworkPatterns: [],
|
||||
treeSitterQueries: '',
|
||||
typeConfig: {
|
||||
declarationNodeTypes: new Set(),
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import { createImportResolver } from '../import-resolvers/resolver-factory.js';
|
|||
import { csharpImportConfig } from '../import-resolvers/configs/csharp.js';
|
||||
import { extractCSharpNamedBindings } from '../named-bindings/csharp.js';
|
||||
import { CSHARP_QUERIES } from '../tree-sitter-queries.js';
|
||||
import type { AstFrameworkPatternConfig } from '../language-provider.js';
|
||||
import { createCallExtractor } from '../call-extractors/generic.js';
|
||||
import { csharpCallConfig } from '../call-extractors/configs/csharp.js';
|
||||
import { createFieldExtractor } from '../field-extractors/generic.js';
|
||||
|
|
@ -135,6 +136,55 @@ const BUILT_INS: ReadonlySet<string> = new Set([
|
|||
export const csharpProvider = defineLanguage({
|
||||
id: SupportedLanguages.CSharp,
|
||||
extensions: ['.cs'],
|
||||
entryPointPatterns: [
|
||||
/^(Get|Post|Put|Delete|Patch)/,
|
||||
/Action$/,
|
||||
/^On[A-Z]/,
|
||||
/Async$/,
|
||||
/^Configure$/,
|
||||
/^ConfigureServices$/,
|
||||
/^Handle$/,
|
||||
/^Execute$/,
|
||||
/^Invoke$/,
|
||||
/^Map[A-Z]/,
|
||||
/Service$/,
|
||||
/^Seed/,
|
||||
],
|
||||
astFrameworkPatterns: [
|
||||
{
|
||||
framework: 'aspnet',
|
||||
entryPointMultiplier: 3.2,
|
||||
reason: 'aspnet-attribute',
|
||||
patterns: [
|
||||
'[ApiController]',
|
||||
'[HttpGet]',
|
||||
'[HttpPost]',
|
||||
'[HttpPut]',
|
||||
'[HttpDelete]',
|
||||
'[Route]',
|
||||
'[Authorize]',
|
||||
'[AllowAnonymous]',
|
||||
],
|
||||
},
|
||||
{
|
||||
framework: 'signalr',
|
||||
entryPointMultiplier: 2.8,
|
||||
reason: 'signalr-attribute',
|
||||
patterns: ['[HubMethodName]', ': Hub', ': Hub<'],
|
||||
},
|
||||
{
|
||||
framework: 'blazor',
|
||||
entryPointMultiplier: 2.5,
|
||||
reason: 'blazor-attribute',
|
||||
patterns: ['@page', '[Parameter]', '@inject'],
|
||||
},
|
||||
{
|
||||
framework: 'efcore',
|
||||
entryPointMultiplier: 2.0,
|
||||
reason: 'efcore-pattern',
|
||||
patterns: ['DbContext', 'DbSet<', 'OnModelCreating'],
|
||||
},
|
||||
] satisfies AstFrameworkPatternConfig[],
|
||||
treeSitterQueries: CSHARP_QUERIES,
|
||||
typeConfig: csharpConfig,
|
||||
exportChecker: csharpExportChecker,
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import { SupportedLanguages } from 'gitnexus-shared';
|
|||
import { createClassExtractor } from '../class-extractors/generic.js';
|
||||
import { dartClassConfig } from '../class-extractors/configs/dart.js';
|
||||
import { defineLanguage } from '../language-provider.js';
|
||||
import type { AstFrameworkPatternConfig } from '../language-provider.js';
|
||||
import { typeConfig as dartConfig } from '../type-extractors/dart.js';
|
||||
import { dartExportChecker } from '../export-detection.js';
|
||||
import { createImportResolver } from '../import-resolvers/resolver-factory.js';
|
||||
|
|
@ -93,6 +94,42 @@ const BUILT_INS: ReadonlySet<string> = new Set([
|
|||
export const dartProvider = defineLanguage({
|
||||
id: SupportedLanguages.Dart,
|
||||
extensions: ['.dart'],
|
||||
entryPointPatterns: [
|
||||
/^main$/,
|
||||
/^build$/,
|
||||
/^createState$/,
|
||||
/^initState$/,
|
||||
/^dispose$/,
|
||||
/^didChangeDependencies$/,
|
||||
/^didUpdateWidget$/,
|
||||
/^runApp$/,
|
||||
/^onEvent$/,
|
||||
/^mapEventToState$/,
|
||||
],
|
||||
astFrameworkPatterns: [
|
||||
{
|
||||
framework: 'flutter',
|
||||
entryPointMultiplier: 2.5,
|
||||
reason: 'flutter-widget',
|
||||
patterns: [
|
||||
'StatelessWidget',
|
||||
'StatefulWidget',
|
||||
'BuildContext',
|
||||
'Widget build',
|
||||
'ChangeNotifier',
|
||||
'GetxController',
|
||||
'Cubit<',
|
||||
'Bloc<',
|
||||
'ConsumerWidget',
|
||||
],
|
||||
},
|
||||
{
|
||||
framework: 'riverpod',
|
||||
entryPointMultiplier: 2.8,
|
||||
reason: 'riverpod-pattern',
|
||||
patterns: ['@riverpod', 'ref.watch', 'ref.read', 'AsyncNotifier', 'Notifier'],
|
||||
},
|
||||
],
|
||||
treeSitterQueries: DART_QUERIES,
|
||||
typeConfig: dartConfig,
|
||||
exportChecker: dartExportChecker,
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import { goExportChecker } from '../export-detection.js';
|
|||
import { createImportResolver } from '../import-resolvers/resolver-factory.js';
|
||||
import { goImportConfig } from '../import-resolvers/configs/go.js';
|
||||
import { GO_QUERIES } from '../tree-sitter-queries.js';
|
||||
import type { AstFrameworkPatternConfig } from '../language-provider.js';
|
||||
import { createFieldExtractor } from '../field-extractors/generic.js';
|
||||
import { goConfig as goFieldConfig } from '../field-extractors/configs/go.js';
|
||||
import { createMethodExtractor } from '../method-extractors/generic.js';
|
||||
|
|
@ -32,6 +33,45 @@ import { goHeritageConfig } from '../heritage-extractors/configs/go.js';
|
|||
export const goProvider = defineLanguage({
|
||||
id: SupportedLanguages.Go,
|
||||
extensions: ['.go'],
|
||||
entryPointPatterns: [/Handler$/, /^Serve/, /^New[A-Z]/, /^Make[A-Z]/],
|
||||
astFrameworkPatterns: [
|
||||
{
|
||||
framework: 'go-http',
|
||||
entryPointMultiplier: 2.5,
|
||||
reason: 'go-http-handler',
|
||||
patterns: [
|
||||
'http.Handler',
|
||||
'http.HandlerFunc',
|
||||
'ServeHTTP',
|
||||
'http.ResponseWriter',
|
||||
'http.Request',
|
||||
],
|
||||
},
|
||||
{
|
||||
framework: 'gin',
|
||||
entryPointMultiplier: 3.0,
|
||||
reason: 'gin-handler',
|
||||
patterns: ['gin.Context', 'gin.Default', 'gin.New'],
|
||||
},
|
||||
{
|
||||
framework: 'echo',
|
||||
entryPointMultiplier: 3.0,
|
||||
reason: 'echo-handler',
|
||||
patterns: ['echo.Context', 'echo.New'],
|
||||
},
|
||||
{
|
||||
framework: 'fiber',
|
||||
entryPointMultiplier: 3.0,
|
||||
reason: 'fiber-handler',
|
||||
patterns: ['fiber.Ctx', 'fiber.New', 'fiber.App'],
|
||||
},
|
||||
{
|
||||
framework: 'go-grpc',
|
||||
entryPointMultiplier: 2.8,
|
||||
reason: 'grpc-service',
|
||||
patterns: ['grpc.Server', 'RegisterServer', 'pb.Unimplemented'],
|
||||
},
|
||||
] satisfies AstFrameworkPatternConfig[],
|
||||
treeSitterQueries: GO_QUERIES,
|
||||
typeConfig: goConfig,
|
||||
exportChecker: goExportChecker,
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import { SupportedLanguages } from 'gitnexus-shared';
|
|||
import { createClassExtractor } from '../class-extractors/generic.js';
|
||||
import { javaClassConfig } from '../class-extractors/configs/jvm.js';
|
||||
import { defineLanguage } from '../language-provider.js';
|
||||
import type { AstFrameworkPatternConfig } from '../language-provider.js';
|
||||
import { javaTypeConfig } from '../type-extractors/jvm.js';
|
||||
import { javaExportChecker } from '../export-detection.js';
|
||||
import { createImportResolver } from '../import-resolvers/resolver-factory.js';
|
||||
|
|
@ -30,6 +31,27 @@ import { createHeritageExtractor } from '../heritage-extractors/generic.js';
|
|||
export const javaProvider = defineLanguage({
|
||||
id: SupportedLanguages.Java,
|
||||
extensions: ['.java'],
|
||||
entryPointPatterns: [/^do[A-Z]/, /^create[A-Z]/, /^build[A-Z]/, /Service$/],
|
||||
astFrameworkPatterns: [
|
||||
{
|
||||
framework: 'spring',
|
||||
entryPointMultiplier: 3.2,
|
||||
reason: 'spring-annotation',
|
||||
patterns: [
|
||||
'@RestController',
|
||||
'@Controller',
|
||||
'@GetMapping',
|
||||
'@PostMapping',
|
||||
'@RequestMapping',
|
||||
],
|
||||
},
|
||||
{
|
||||
framework: 'jaxrs',
|
||||
entryPointMultiplier: 3.0,
|
||||
reason: 'jaxrs-annotation',
|
||||
patterns: ['@Path', '@GET', '@POST', '@PUT', '@DELETE'],
|
||||
},
|
||||
] satisfies AstFrameworkPatternConfig[],
|
||||
treeSitterQueries: JAVA_QUERIES,
|
||||
typeConfig: javaTypeConfig,
|
||||
exportChecker: javaExportChecker,
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import { kotlinImportConfig } from '../import-resolvers/configs/jvm.js';
|
|||
import { extractKotlinNamedBindings } from '../named-bindings/kotlin.js';
|
||||
import { appendKotlinWildcard } from '../import-resolvers/jvm.js';
|
||||
import { KOTLIN_QUERIES } from '../tree-sitter-queries.js';
|
||||
import type { AstFrameworkPatternConfig } from '../language-provider.js';
|
||||
import type { SyntaxNode } from '../utils/ast-helpers.js';
|
||||
import { createCallExtractor } from '../call-extractors/generic.js';
|
||||
import { kotlinCallConfig } from '../call-extractors/configs/jvm.js';
|
||||
|
|
@ -105,6 +106,47 @@ const BUILT_INS: ReadonlySet<string> = new Set([
|
|||
export const kotlinProvider = defineLanguage({
|
||||
id: SupportedLanguages.Kotlin,
|
||||
extensions: ['.kt', '.kts'],
|
||||
entryPointPatterns: [
|
||||
/^on(Create|Start|Resume|Pause|Stop|Destroy)$/,
|
||||
/^do[A-Z]/,
|
||||
/^create[A-Z]/,
|
||||
/^build[A-Z]/,
|
||||
/ViewModel$/,
|
||||
/^module$/,
|
||||
/Service$/,
|
||||
],
|
||||
astFrameworkPatterns: [
|
||||
{
|
||||
framework: 'spring-kotlin',
|
||||
entryPointMultiplier: 3.2,
|
||||
reason: 'spring-kotlin-annotation',
|
||||
patterns: [
|
||||
'@RestController',
|
||||
'@Controller',
|
||||
'@GetMapping',
|
||||
'@PostMapping',
|
||||
'@RequestMapping',
|
||||
],
|
||||
},
|
||||
{
|
||||
framework: 'jaxrs',
|
||||
entryPointMultiplier: 3.0,
|
||||
reason: 'jaxrs-annotation',
|
||||
patterns: ['@Path', '@GET', '@POST', '@PUT', '@DELETE'],
|
||||
},
|
||||
{
|
||||
framework: 'ktor',
|
||||
entryPointMultiplier: 2.8,
|
||||
reason: 'ktor-routing',
|
||||
patterns: ['routing', 'embeddedServer', 'Application.module'],
|
||||
},
|
||||
{
|
||||
framework: 'android-kotlin',
|
||||
entryPointMultiplier: 2.5,
|
||||
reason: 'android-annotation',
|
||||
patterns: ['@AndroidEntryPoint', 'AppCompatActivity', 'Fragment('],
|
||||
},
|
||||
] satisfies AstFrameworkPatternConfig[],
|
||||
treeSitterQueries: KOTLIN_QUERIES,
|
||||
typeConfig: kotlinTypeConfig,
|
||||
exportChecker: kotlinExportChecker,
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import { SupportedLanguages } from 'gitnexus-shared';
|
|||
import { createClassExtractor } from '../class-extractors/generic.js';
|
||||
import { phpClassConfig } from '../class-extractors/configs/php.js';
|
||||
import { defineLanguage } from '../language-provider.js';
|
||||
import type { AstFrameworkPatternConfig } from '../language-provider.js';
|
||||
import { typeConfig as phpConfig } from '../type-extractors/php.js';
|
||||
import { phpExportChecker } from '../export-detection.js';
|
||||
import { createImportResolver } from '../import-resolvers/resolver-factory.js';
|
||||
|
|
@ -239,6 +240,41 @@ function isPhpRouteFile(filePath: string): boolean {
|
|||
export const phpProvider = defineLanguage({
|
||||
id: SupportedLanguages.PHP,
|
||||
extensions: ['.php', '.phtml', '.php3', '.php4', '.php5', '.php8'],
|
||||
entryPointPatterns: [
|
||||
/Controller$/,
|
||||
/^handle$/,
|
||||
/^execute$/,
|
||||
/^boot$/,
|
||||
/^register$/,
|
||||
/^__invoke$/,
|
||||
/^(index|show|store|update|destroy|create|edit)$/,
|
||||
/^(get|post|put|delete|patch)[A-Z]/,
|
||||
/^run$/,
|
||||
/^fire$/,
|
||||
/^dispatch$/,
|
||||
/Service$/,
|
||||
/Repository$/,
|
||||
/^find$/,
|
||||
/^findAll$/,
|
||||
/^save$/,
|
||||
/^delete$/,
|
||||
],
|
||||
astFrameworkPatterns: [
|
||||
{
|
||||
framework: 'laravel',
|
||||
entryPointMultiplier: 3.0,
|
||||
reason: 'php-route-attribute',
|
||||
patterns: [
|
||||
'Route::get',
|
||||
'Route::post',
|
||||
'Route::put',
|
||||
'Route::delete',
|
||||
'Route::resource',
|
||||
'Route::apiResource',
|
||||
'#[Route(',
|
||||
],
|
||||
},
|
||||
],
|
||||
treeSitterQueries: PHP_QUERIES,
|
||||
typeConfig: phpConfig,
|
||||
exportChecker: phpExportChecker,
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import { SupportedLanguages } from 'gitnexus-shared';
|
|||
import { createClassExtractor } from '../class-extractors/generic.js';
|
||||
import { pythonClassConfig } from '../class-extractors/configs/python.js';
|
||||
import { defineLanguage } from '../language-provider.js';
|
||||
import type { AstFrameworkPatternConfig } from '../language-provider.js';
|
||||
import { typeConfig as pythonConfig } from '../type-extractors/python.js';
|
||||
import { pythonExportChecker } from '../export-detection.js';
|
||||
import { createImportResolver } from '../import-resolvers/resolver-factory.js';
|
||||
|
|
@ -106,6 +107,21 @@ function normalizePythonStringLiteral(text: string): string | undefined {
|
|||
export const pythonProvider = defineLanguage({
|
||||
id: SupportedLanguages.Python,
|
||||
extensions: ['.py'],
|
||||
entryPointPatterns: [/^app$/, /^(get|post|put|delete|patch)_/i, /^api_/, /^view_/],
|
||||
astFrameworkPatterns: [
|
||||
{
|
||||
framework: 'fastapi',
|
||||
entryPointMultiplier: 3.0,
|
||||
reason: 'fastapi-decorator',
|
||||
patterns: ['@app.get', '@app.post', '@app.put', '@app.delete', '@router.get'],
|
||||
},
|
||||
{
|
||||
framework: 'flask',
|
||||
entryPointMultiplier: 2.8,
|
||||
reason: 'flask-decorator',
|
||||
patterns: ['@app.route', '@blueprint.route'],
|
||||
},
|
||||
] satisfies AstFrameworkPatternConfig[],
|
||||
treeSitterQueries: PYTHON_QUERIES,
|
||||
typeConfig: pythonConfig,
|
||||
exportChecker: pythonExportChecker,
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import type { NodeLabel } from 'gitnexus-shared';
|
|||
import { createClassExtractor } from '../class-extractors/generic.js';
|
||||
import { rubyClassConfig } from '../class-extractors/configs/ruby.js';
|
||||
import { defineLanguage } from '../language-provider.js';
|
||||
import type { AstFrameworkPatternConfig } from '../language-provider.js';
|
||||
import type { SyntaxNode } from '../utils/ast-helpers.js';
|
||||
import { typeConfig as rubyConfig } from '../type-extractors/ruby.js';
|
||||
import { routeRubyCall } from '../call-routing.js';
|
||||
|
|
@ -151,6 +152,31 @@ const rubyResolveEnclosingOwner = (node: SyntaxNode): SyntaxNode | null => {
|
|||
export const rubyProvider = defineLanguage({
|
||||
id: SupportedLanguages.Ruby,
|
||||
extensions: ['.rb', '.rake', '.gemspec'],
|
||||
entryPointPatterns: [/^call$/, /^perform$/, /^execute$/],
|
||||
astFrameworkPatterns: [
|
||||
{
|
||||
framework: 'rails',
|
||||
entryPointMultiplier: 3.0,
|
||||
reason: 'rails-pattern',
|
||||
patterns: [
|
||||
'ApplicationController',
|
||||
'ApplicationRecord',
|
||||
'ActiveRecord::Base',
|
||||
'before_action',
|
||||
'after_action',
|
||||
'has_many',
|
||||
'belongs_to',
|
||||
'has_one',
|
||||
'validates',
|
||||
],
|
||||
},
|
||||
{
|
||||
framework: 'sinatra',
|
||||
entryPointMultiplier: 2.8,
|
||||
reason: 'sinatra-pattern',
|
||||
patterns: ['Sinatra::Base', 'Sinatra::Application'],
|
||||
},
|
||||
],
|
||||
treeSitterQueries: RUBY_QUERIES,
|
||||
typeConfig: rubyConfig,
|
||||
exportChecker: rubyExportChecker,
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import { createImportResolver } from '../import-resolvers/resolver-factory.js';
|
|||
import { rustImportConfig } from '../import-resolvers/configs/rust.js';
|
||||
import { extractRustNamedBindings } from '../named-bindings/rust.js';
|
||||
import { RUST_QUERIES } from '../tree-sitter-queries.js';
|
||||
import type { AstFrameworkPatternConfig } from '../language-provider.js';
|
||||
import { createFieldExtractor } from '../field-extractors/generic.js';
|
||||
import { rustConfig as rustFieldConfig } from '../field-extractors/configs/rust.js';
|
||||
import { createMethodExtractor } from '../method-extractors/generic.js';
|
||||
|
|
@ -121,6 +122,41 @@ const BUILT_INS: ReadonlySet<string> = new Set([
|
|||
export const rustProvider = defineLanguage({
|
||||
id: SupportedLanguages.Rust,
|
||||
extensions: ['.rs'],
|
||||
entryPointPatterns: [/^(get|post|put|delete)_handler$/i, /^handle_/, /^new$/, /^run$/, /^spawn/],
|
||||
astFrameworkPatterns: [
|
||||
{
|
||||
framework: 'actix-web',
|
||||
entryPointMultiplier: 3.0,
|
||||
reason: 'actix-attribute',
|
||||
patterns: [
|
||||
'#[get',
|
||||
'#[post',
|
||||
'#[put',
|
||||
'#[delete',
|
||||
'#[actix_web',
|
||||
'HttpRequest',
|
||||
'HttpResponse',
|
||||
],
|
||||
},
|
||||
{
|
||||
framework: 'axum',
|
||||
entryPointMultiplier: 3.0,
|
||||
reason: 'axum-routing',
|
||||
patterns: ['Router::new', 'axum::extract', 'axum::routing'],
|
||||
},
|
||||
{
|
||||
framework: 'rocket',
|
||||
entryPointMultiplier: 3.0,
|
||||
reason: 'rocket-attribute',
|
||||
patterns: ['#[get', '#[post', '#[launch', 'rocket::'],
|
||||
},
|
||||
{
|
||||
framework: 'tokio',
|
||||
entryPointMultiplier: 2.5,
|
||||
reason: 'tokio-runtime',
|
||||
patterns: ['#[tokio::main]', '#[tokio::test]'],
|
||||
},
|
||||
] satisfies AstFrameworkPatternConfig[],
|
||||
treeSitterQueries: RUST_QUERIES,
|
||||
typeConfig: rustConfig,
|
||||
exportChecker: rustExportChecker,
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import type { NodeLabel, SymbolDefinition } from 'gitnexus-shared';
|
|||
import { createClassExtractor } from '../class-extractors/generic.js';
|
||||
import { swiftClassConfig } from '../class-extractors/configs/swift.js';
|
||||
import { defineLanguage } from '../language-provider.js';
|
||||
import type { AstFrameworkPatternConfig } from '../language-provider.js';
|
||||
import { typeConfig as swiftConfig } from '../type-extractors/swift.js';
|
||||
import { swiftExportChecker } from '../export-detection.js';
|
||||
import { createImportResolver } from '../import-resolvers/resolver-factory.js';
|
||||
|
|
@ -259,6 +260,60 @@ const BUILT_INS: ReadonlySet<string> = new Set([
|
|||
export const swiftProvider = defineLanguage({
|
||||
id: SupportedLanguages.Swift,
|
||||
extensions: ['.swift'],
|
||||
entryPointPatterns: [
|
||||
/^viewDidLoad$/,
|
||||
/^viewWillAppear$/,
|
||||
/^viewDidAppear$/,
|
||||
/^viewWillDisappear$/,
|
||||
/^viewDidDisappear$/,
|
||||
/^application\(/,
|
||||
/^scene\(/,
|
||||
/^body$/,
|
||||
/Coordinator$/,
|
||||
/^sceneDidBecomeActive$/,
|
||||
/^sceneWillResignActive$/,
|
||||
/^didFinishLaunchingWithOptions$/,
|
||||
/ViewController$/,
|
||||
/^configure[A-Z]/,
|
||||
/^setup[A-Z]/,
|
||||
/^makeBody$/,
|
||||
],
|
||||
astFrameworkPatterns: [
|
||||
{
|
||||
framework: 'uikit',
|
||||
entryPointMultiplier: 2.5,
|
||||
reason: 'uikit-lifecycle',
|
||||
patterns: [
|
||||
'viewDidLoad',
|
||||
'viewWillAppear',
|
||||
'viewDidAppear',
|
||||
'UIViewController',
|
||||
'@IBOutlet',
|
||||
'@IBAction',
|
||||
'@objc',
|
||||
],
|
||||
},
|
||||
{
|
||||
framework: 'swiftui',
|
||||
entryPointMultiplier: 2.8,
|
||||
reason: 'swiftui-pattern',
|
||||
patterns: [
|
||||
'@main',
|
||||
'WindowGroup',
|
||||
'ContentView',
|
||||
'@StateObject',
|
||||
'@ObservedObject',
|
||||
'@EnvironmentObject',
|
||||
'@Published',
|
||||
],
|
||||
},
|
||||
{
|
||||
framework: 'vapor',
|
||||
entryPointMultiplier: 3.0,
|
||||
reason: 'vapor-routing',
|
||||
patterns: ['app.get', 'app.post', 'req.content.decode', 'Vapor'],
|
||||
},
|
||||
],
|
||||
treeSitterQueries: SWIFT_QUERIES,
|
||||
typeConfig: swiftConfig,
|
||||
exportChecker: swiftExportChecker,
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import { SupportedLanguages } from 'gitnexus-shared';
|
||||
import type { NodeLabel } from 'gitnexus-shared';
|
||||
import { defineLanguage } from '../language-provider.js';
|
||||
import type { AstFrameworkPatternConfig } from '../language-provider.js';
|
||||
import { createClassExtractor } from '../class-extractors/generic.js';
|
||||
import {
|
||||
typescriptClassConfig,
|
||||
|
|
@ -217,6 +218,29 @@ export const BUILT_INS: ReadonlySet<string> = new Set([
|
|||
export const typescriptProvider = defineLanguage({
|
||||
id: SupportedLanguages.TypeScript,
|
||||
extensions: ['.ts', '.tsx'],
|
||||
entryPointPatterns: [/^use[A-Z]/],
|
||||
astFrameworkPatterns: [
|
||||
{
|
||||
framework: 'nestjs',
|
||||
entryPointMultiplier: 3.2,
|
||||
reason: 'nestjs-decorator',
|
||||
patterns: ['@Controller', '@Get', '@Post', '@Put', '@Delete', '@Patch'],
|
||||
},
|
||||
{
|
||||
framework: 'expo-router',
|
||||
entryPointMultiplier: 2.5,
|
||||
reason: 'expo-router-navigation',
|
||||
patterns: [
|
||||
'router.push',
|
||||
'router.replace',
|
||||
'router.navigate',
|
||||
'useRouter',
|
||||
'useLocalSearchParams',
|
||||
'useSegments',
|
||||
'expo-router',
|
||||
],
|
||||
},
|
||||
] satisfies AstFrameworkPatternConfig[],
|
||||
treeSitterQueries: TYPESCRIPT_QUERIES,
|
||||
typeConfig: typescriptConfig,
|
||||
exportChecker: tsExportChecker,
|
||||
|
|
@ -256,6 +280,29 @@ export const typescriptProvider = defineLanguage({
|
|||
export const javascriptProvider = defineLanguage({
|
||||
id: SupportedLanguages.JavaScript,
|
||||
extensions: ['.js', '.jsx'],
|
||||
entryPointPatterns: [/^use[A-Z]/],
|
||||
astFrameworkPatterns: [
|
||||
{
|
||||
framework: 'nestjs',
|
||||
entryPointMultiplier: 3.2,
|
||||
reason: 'nestjs-decorator',
|
||||
patterns: ['@Controller', '@Get', '@Post', '@Put', '@Delete', '@Patch'],
|
||||
},
|
||||
{
|
||||
framework: 'expo-router',
|
||||
entryPointMultiplier: 2.5,
|
||||
reason: 'expo-router-navigation',
|
||||
patterns: [
|
||||
'router.push',
|
||||
'router.replace',
|
||||
'router.navigate',
|
||||
'useRouter',
|
||||
'useLocalSearchParams',
|
||||
'useSegments',
|
||||
'expo-router',
|
||||
],
|
||||
},
|
||||
] satisfies AstFrameworkPatternConfig[],
|
||||
treeSitterQueries: JAVASCRIPT_QUERIES,
|
||||
typeConfig: typescriptConfig,
|
||||
exportChecker: tsExportChecker,
|
||||
|
|
|
|||
|
|
@ -68,6 +68,8 @@ const vueClassExtractor = createClassExtractor(vueClassConfig);
|
|||
export const vueProvider = defineLanguage({
|
||||
id: SupportedLanguages.Vue,
|
||||
extensions: ['.vue'],
|
||||
entryPointPatterns: [],
|
||||
astFrameworkPatterns: [],
|
||||
treeSitterQueries: TYPESCRIPT_QUERIES,
|
||||
typeConfig: typescriptConfig,
|
||||
exportChecker: tsExportChecker,
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ import { describe, it, expect } from 'vitest';
|
|||
import {
|
||||
detectFrameworkFromPath,
|
||||
detectFrameworkFromAST,
|
||||
FRAMEWORK_AST_PATTERNS,
|
||||
} from '../../src/core/ingestion/framework-detection.js';
|
||||
import { providers } from '../../src/core/ingestion/languages/index.js';
|
||||
|
||||
describe('detectFrameworkFromPath', () => {
|
||||
describe('Next.js', () => {
|
||||
|
|
@ -359,24 +359,26 @@ describe('detectFrameworkFromAST', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('FRAMEWORK_AST_PATTERNS', () => {
|
||||
it('has patterns for all expected frameworks', () => {
|
||||
const expectedFrameworks = [
|
||||
describe('provider astFrameworkPatterns', () => {
|
||||
it('covers all expected frameworks across providers', () => {
|
||||
const expectedFrameworks = new Set([
|
||||
'nestjs',
|
||||
'expo-router',
|
||||
'express',
|
||||
'fastapi',
|
||||
'flask',
|
||||
'spring',
|
||||
'jaxrs',
|
||||
'aspnet',
|
||||
'signalr',
|
||||
'blazor',
|
||||
'efcore',
|
||||
'go-http',
|
||||
'gin',
|
||||
'echo',
|
||||
'fiber',
|
||||
'go-grpc',
|
||||
'laravel',
|
||||
'actix',
|
||||
'actix-web',
|
||||
'axum',
|
||||
'rocket',
|
||||
'tokio',
|
||||
|
|
@ -386,12 +388,21 @@ describe('FRAMEWORK_AST_PATTERNS', () => {
|
|||
'vapor',
|
||||
'rails',
|
||||
'sinatra',
|
||||
];
|
||||
'spring-kotlin',
|
||||
'ktor',
|
||||
'android-kotlin',
|
||||
'flutter',
|
||||
'riverpod',
|
||||
]);
|
||||
const foundFrameworks = new Set<string>();
|
||||
for (const provider of Object.values(providers)) {
|
||||
for (const cfg of provider.astFrameworkPatterns ?? []) {
|
||||
foundFrameworks.add(cfg.framework);
|
||||
expect(cfg.patterns.length).toBeGreaterThan(0);
|
||||
}
|
||||
}
|
||||
for (const fw of expectedFrameworks) {
|
||||
expect(FRAMEWORK_AST_PATTERNS).toHaveProperty(fw);
|
||||
expect(
|
||||
FRAMEWORK_AST_PATTERNS[fw as keyof typeof FRAMEWORK_AST_PATTERNS].length,
|
||||
).toBeGreaterThan(0);
|
||||
expect(foundFrameworks.has(fw), `missing framework: ${fw}`).toBe(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue