@@ -10,6 +10,12 @@ import { QueryCapture } from "web-tree-sitter"
1010// Private constant
1111const DEFAULT_MIN_COMPONENT_LINES_VALUE = 4
1212
13+ // Language-specific rules
14+ const LANGUAGE_SKIP_RULES : Record < string , string [ ] > = {
15+ java : [ "definition.method" ] ,
16+ // Future languages can be added here
17+ }
18+
1319// Getter function for MIN_COMPONENT_LINES (for easier testing)
1420let currentMinComponentLines = DEFAULT_MIN_COMPONENT_LINES_VALUE
1521
@@ -27,6 +33,14 @@ export function setMinComponentLines(value: number): void {
2733 currentMinComponentLines = value
2834}
2935
36+ function shouldSkipLineCountCheck ( lineCount : number , capture : QueryCapture , language : string ) {
37+ const skipRules = LANGUAGE_SKIP_RULES [ language ]
38+ if ( skipRules && skipRules . includes ( capture . name ) ) {
39+ return false
40+ }
41+ return lineCount < getMinComponentLines ( )
42+ }
43+
3044const extensions = [
3145 "tla" ,
3246 "js" ,
@@ -310,7 +324,7 @@ function processCaptures(captures: QueryCapture[], lines: string[], language: st
310324 const lineCount = endLine - startLine + 1
311325
312326 // Skip components that don't span enough lines
313- if ( shouldSkip ( lineCount , capture , language ) ) {
327+ if ( shouldSkipLineCountCheck ( lineCount , capture , language ) ) {
314328 return
315329 }
316330
@@ -324,9 +338,9 @@ function processCaptures(captures: QueryCapture[], lines: string[], language: st
324338 }
325339
326340 let outputLineIdx = startLine
327- // For Java method definitions, find the first non-annotation line
341+ // For Java method definitions, find the actual method signature line
328342 if ( language === "java" && name === "definition.method" ) {
329- outputLineIdx = skipJavaAnnotations ( lines , startLine , endLine )
343+ outputLineIdx = findJavaMethodSignatureLine ( lines , startLine , endLine )
330344 }
331345
332346 // Check if this is a valid component definition (not an HTML element)
@@ -419,84 +433,46 @@ async function parseFile(
419433 return null
420434 }
421435}
422- function shouldSkip ( lineCount : number , capture : QueryCapture , language : string ) {
423- if ( language === "java" ) {
424- if ( [ "definition.method" ] . includes ( capture . name ) ) {
425- return false
426- }
427- }
428- return lineCount < getMinComponentLines ( )
429- }
430436
431437/**
432- * Skip Java annotations and find the first line that contains the actual method declaration
438+ * Find the line containing the actual Java method signature
439+ * by looking for lines that match method declaration patterns
433440 *
434441 * @param lines - Array of lines from the file
435442 * @param startLine - Starting line index
436443 * @param endLine - Ending line index
437- * @returns The line index of the first non-annotation line
444+ * @returns The line index of the method signature
438445 */
439- function skipJavaAnnotations ( lines : string [ ] , startLine : number , endLine : number ) : number {
440- let currentLine = startLine
441- let inAnnotation = false
442- let annotationDepth = 0
443-
444- while ( currentLine <= endLine ) {
445- const line = lines [ currentLine ] . trim ( )
446-
447- // Skip empty lines
448- if ( line . length === 0 ) {
449- currentLine ++
446+ function findJavaMethodSignatureLine ( lines : string [ ] , startLine : number , endLine : number ) : number {
447+ // Java method signature pattern:
448+ // - May start with access modifiers (public, private, protected, static, final, etc.)
449+ // - Followed by return type
450+ // - Followed by method name
451+ // - Followed by parentheses
452+ const methodSignaturePattern =
453+ / ^ \s * ( p u b l i c | p r i v a t e | p r o t e c t e d | s t a t i c | f i n a l | a b s t r a c t | s y n c h r o n i z e d | n a t i v e | s t r i c t f p | \w + \s + ) * \w + \s * \( /
454+
455+ for ( let i = startLine ; i <= endLine ; i ++ ) {
456+ const line = lines [ i ] . trim ( )
457+
458+ // Skip empty lines and annotation lines
459+ if ( line . length === 0 || line . startsWith ( "@" ) ) {
450460 continue
451461 }
452462
453- // Check if this line starts an annotation
454- if ( line . startsWith ( "@" ) ) {
455- inAnnotation = true
456- annotationDepth = 0
457-
458- // Count opening and closing parentheses to track annotation completion
459- for ( const char of line ) {
460- if ( char === "(" ) {
461- annotationDepth ++
462- } else if ( char === ")" ) {
463- annotationDepth --
464- }
465- }
466-
467- // If annotation is complete on this line, mark as not in annotation
468- if ( annotationDepth <= 0 ) {
469- inAnnotation = false
470- }
471-
472- currentLine ++
473- continue
463+ // Check if this line looks like a method signature
464+ if ( methodSignaturePattern . test ( line ) ) {
465+ return i
474466 }
467+ }
475468
476- // If we're still inside a multi-line annotation
477- if ( inAnnotation ) {
478- // Count parentheses to track when annotation ends
479- for ( const char of line ) {
480- if ( char === "(" ) {
481- annotationDepth ++
482- } else if ( char === ")" ) {
483- annotationDepth --
484- }
485- }
486-
487- // If annotation is complete, mark as not in annotation
488- if ( annotationDepth <= 0 ) {
489- inAnnotation = false
490- }
491-
492- currentLine ++
493- continue
469+ // If no method signature found, return the first non-annotation, non-empty line
470+ for ( let i = startLine ; i <= endLine ; i ++ ) {
471+ const line = lines [ i ] . trim ( )
472+ if ( line . length > 0 && ! line . startsWith ( "@" ) ) {
473+ return i
494474 }
495-
496- // If we're not in an annotation and this line has content, this is our target
497- return currentLine
498475 }
499476
500- // If we couldn't find a non-annotation line, return the start line
501477 return startLine
502478}
0 commit comments