@@ -25,7 +25,7 @@ export const goResolver: FrameworkResolver = {
2525 resolve ( ref : UnresolvedRef , context : ResolutionContext ) : ResolvedRef | null {
2626 // Pattern 1: Handler references
2727 if ( ref . referenceName . endsWith ( 'Handler' ) || ref . referenceName . startsWith ( 'Handle' ) ) {
28- const result = resolveHandler ( ref . referenceName , context ) ;
28+ const result = resolveByNameAndKind ( ref . referenceName , 'function' , HANDLER_DIRS , context ) ;
2929 if ( result ) {
3030 return {
3131 original : ref ,
@@ -38,7 +38,7 @@ export const goResolver: FrameworkResolver = {
3838
3939 // Pattern 2: Service/Repository references
4040 if ( ref . referenceName . endsWith ( 'Service' ) || ref . referenceName . endsWith ( 'Repository' ) || ref . referenceName . endsWith ( 'Store' ) ) {
41- const result = resolveService ( ref . referenceName , context ) ;
41+ const result = resolveByNameAndKind ( ref . referenceName , null , SERVICE_DIRS , context , SERVICE_KINDS ) ;
4242 if ( result ) {
4343 return {
4444 original : ref ,
@@ -51,7 +51,7 @@ export const goResolver: FrameworkResolver = {
5151
5252 // Pattern 3: Middleware references
5353 if ( ref . referenceName . endsWith ( 'Middleware' ) || ref . referenceName . startsWith ( 'Auth' ) || ref . referenceName . startsWith ( 'Log' ) ) {
54- const result = resolveMiddleware ( ref . referenceName , context ) ;
54+ const result = resolveByNameAndKind ( ref . referenceName , 'function' , MIDDLEWARE_DIRS , context ) ;
5555 if ( result ) {
5656 return {
5757 original : ref ,
@@ -64,7 +64,7 @@ export const goResolver: FrameworkResolver = {
6464
6565 // Pattern 4: Model/Entity references (typically PascalCase structs)
6666 if ( / ^ [ A - Z ] [ a - z A - Z ] + $ / . test ( ref . referenceName ) ) {
67- const result = resolveModel ( ref . referenceName , context ) ;
67+ const result = resolveByNameAndKind ( ref . referenceName , 'struct' , MODEL_DIRS , context ) ;
6868 if ( result ) {
6969 return {
7070 original : ref ,
@@ -178,93 +178,43 @@ export const goResolver: FrameworkResolver = {
178178 } ,
179179} ;
180180
181- // Helper functions
181+ // Directory patterns for framework resolution
182+ const HANDLER_DIRS = [ 'handler' , 'handlers' , 'api' , 'routes' , 'controller' , 'controllers' ] ;
183+ const SERVICE_DIRS = [ 'service' , 'services' , 'repository' , 'store' , 'pkg' ] ;
184+ const MIDDLEWARE_DIRS = [ 'middleware' , 'middlewares' ] ;
185+ const MODEL_DIRS = [ 'model' , 'models' , 'entity' , 'entities' , 'domain' , 'pkg' ] ;
186+ const SERVICE_KINDS = new Set ( [ 'struct' , 'interface' ] ) ;
182187
183- function resolveHandler ( name : string , context : ResolutionContext ) : string | null {
184- const handlerDirs = [ 'handler' , 'handlers' , 'api' , 'routes' , 'controller' , 'controllers' ] ;
185-
186- const allFiles = context . getAllFiles ( ) ;
187- for ( const file of allFiles ) {
188- if ( file . endsWith ( '.go' ) && handlerDirs . some ( ( d ) => file . includes ( `/${ d } /` ) ) ) {
189- const nodes = context . getNodesInFile ( file ) ;
190- const handlerNode = nodes . find (
191- ( n ) => n . kind === 'function' && n . name === name
192- ) ;
193- if ( handlerNode ) {
194- return handlerNode . id ;
195- }
196- }
197- }
198-
199- // Search all go files
200- for ( const file of allFiles ) {
201- if ( file . endsWith ( '.go' ) ) {
202- const nodes = context . getNodesInFile ( file ) ;
203- const handlerNode = nodes . find (
204- ( n ) => n . kind === 'function' && n . name === name
205- ) ;
206- if ( handlerNode ) {
207- return handlerNode . id ;
208- }
209- }
210- }
211-
212- return null ;
213- }
214-
215- function resolveService ( name : string , context : ResolutionContext ) : string | null {
216- const serviceDirs = [ 'service' , 'services' , 'repository' , 'store' , 'pkg' ] ;
217-
218- const allFiles = context . getAllFiles ( ) ;
219- for ( const file of allFiles ) {
220- if ( file . endsWith ( '.go' ) && serviceDirs . some ( ( d ) => file . includes ( `/${ d } /` ) ) ) {
221- const nodes = context . getNodesInFile ( file ) ;
222- const serviceNode = nodes . find (
223- ( n ) => ( n . kind === 'struct' || n . kind === 'interface' ) && n . name === name
224- ) ;
225- if ( serviceNode ) {
226- return serviceNode . id ;
227- }
228- }
229- }
230-
231- return null ;
232- }
233-
234- function resolveMiddleware ( name : string , context : ResolutionContext ) : string | null {
235- const middlewareDirs = [ 'middleware' , 'middlewares' ] ;
236-
237- const allFiles = context . getAllFiles ( ) ;
238- for ( const file of allFiles ) {
239- if ( file . endsWith ( '.go' ) && middlewareDirs . some ( ( d ) => file . includes ( `/${ d } /` ) ) ) {
240- const nodes = context . getNodesInFile ( file ) ;
241- const mwNode = nodes . find (
242- ( n ) => n . kind === 'function' && n . name === name
243- ) ;
244- if ( mwNode ) {
245- return mwNode . id ;
246- }
247- }
248- }
249-
250- return null ;
251- }
252-
253- function resolveModel ( name : string , context : ResolutionContext ) : string | null {
254- const modelDirs = [ 'model' , 'models' , 'entity' , 'entities' , 'domain' , 'pkg' ] ;
255-
256- const allFiles = context . getAllFiles ( ) ;
257- for ( const file of allFiles ) {
258- if ( file . endsWith ( '.go' ) && modelDirs . some ( ( d ) => file . includes ( `/${ d } /` ) ) ) {
259- const nodes = context . getNodesInFile ( file ) ;
260- const modelNode = nodes . find (
261- ( n ) => n . kind === 'struct' && n . name === name
262- ) ;
263- if ( modelNode ) {
264- return modelNode . id ;
265- }
266- }
267- }
268-
269- return null ;
188+ /**
189+ * Resolve a symbol by name using indexed queries instead of scanning all files.
190+ * Uses getNodesByName (O(log n) indexed lookup) instead of iterating every file.
191+ */
192+ function resolveByNameAndKind (
193+ name : string ,
194+ kind : string | null ,
195+ preferredDirs : string [ ] ,
196+ context : ResolutionContext ,
197+ kinds ?: Set < string >
198+ ) : string | null {
199+ const candidates = context . getNodesByName ( name ) ;
200+ if ( candidates . length === 0 ) return null ;
201+
202+ // Filter by kind
203+ const kindFiltered = candidates . filter ( ( n ) => {
204+ if ( kinds ) return kinds . has ( n . kind ) ;
205+ if ( kind ) return n . kind === kind ;
206+ return true ;
207+ } ) ;
208+
209+ if ( kindFiltered . length === 0 ) return null ;
210+
211+ // Prefer candidates in framework-conventional directories
212+ const preferred = kindFiltered . filter ( ( n ) =>
213+ preferredDirs . some ( ( d ) => n . filePath . includes ( `/${ d } /` ) )
214+ ) ;
215+
216+ if ( preferred . length > 0 ) return preferred [ 0 ] ! . id ;
217+
218+ // Fall back to any match
219+ return kindFiltered [ 0 ] ! . id ;
270220}
0 commit comments