@@ -594,4 +594,117 @@ describe('Scanner', () => {
594594 expect ( docType ?. metadata . imports ) . toEqual ( [ ] ) ;
595595 } ) ;
596596 } ) ;
597+
598+ describe ( 'Callee Extraction' , ( ) => {
599+ it ( 'should extract callees from functions' , async ( ) => {
600+ const result = await scanRepository ( {
601+ repoRoot,
602+ include : [ 'packages/core/src/scanner/index.ts' ] ,
603+ } ) ;
604+
605+ // createDefaultRegistry calls registry.register()
606+ const fn = result . documents . find ( ( d ) => d . metadata . name === 'createDefaultRegistry' ) ;
607+ expect ( fn ) . toBeDefined ( ) ;
608+ expect ( fn ?. metadata . callees ) . toBeDefined ( ) ;
609+ expect ( fn ?. metadata . callees ?. length ) . toBeGreaterThan ( 0 ) ;
610+
611+ // Should have calls to ScannerRegistry constructor and register method
612+ const calleeNames = fn ?. metadata . callees ?. map ( ( c ) => c . name ) || [ ] ;
613+ expect ( calleeNames . some ( ( n ) => n . includes ( 'ScannerRegistry' ) || n . includes ( 'new' ) ) ) . toBe (
614+ true
615+ ) ;
616+ } ) ;
617+
618+ it ( 'should extract callees from methods' , async ( ) => {
619+ const result = await scanRepository ( {
620+ repoRoot,
621+ include : [ 'packages/core/src/scanner/typescript.ts' ] ,
622+ exclude : [ '**/*.test.ts' ] ,
623+ } ) ;
624+
625+ // extractFromSourceFile calls other methods like extractFunction, extractClass
626+ const method = result . documents . find (
627+ ( d ) => d . type === 'method' && d . metadata . name === 'TypeScriptScanner.extractFromSourceFile'
628+ ) ;
629+ expect ( method ) . toBeDefined ( ) ;
630+ expect ( method ?. metadata . callees ) . toBeDefined ( ) ;
631+ expect ( method ?. metadata . callees ?. length ) . toBeGreaterThan ( 0 ) ;
632+
633+ // Should call extractFunction, extractClass, etc.
634+ const calleeNames = method ?. metadata . callees ?. map ( ( c ) => c . name ) || [ ] ;
635+ expect ( calleeNames . some ( ( n ) => n . includes ( 'extractFunction' ) ) ) . toBe ( true ) ;
636+ } ) ;
637+
638+ it ( 'should include line numbers for callees' , async ( ) => {
639+ const result = await scanRepository ( {
640+ repoRoot,
641+ include : [ 'packages/core/src/scanner/index.ts' ] ,
642+ } ) ;
643+
644+ const fn = result . documents . find ( ( d ) => d . metadata . name === 'createDefaultRegistry' ) ;
645+ expect ( fn ?. metadata . callees ) . toBeDefined ( ) ;
646+
647+ for ( const callee of fn ?. metadata . callees || [ ] ) {
648+ expect ( callee . line ) . toBeDefined ( ) ;
649+ expect ( typeof callee . line ) . toBe ( 'number' ) ;
650+ expect ( callee . line ) . toBeGreaterThan ( 0 ) ;
651+ }
652+ } ) ;
653+
654+ it ( 'should not have callees for interfaces' , async ( ) => {
655+ const result = await scanRepository ( {
656+ repoRoot,
657+ include : [ 'packages/core/src/scanner/types.ts' ] ,
658+ } ) ;
659+
660+ // Interfaces don't have callees (no function body)
661+ const iface = result . documents . find ( ( d ) => d . metadata . name === 'Scanner' ) ;
662+ expect ( iface ) . toBeDefined ( ) ;
663+ expect ( iface ?. metadata . callees ) . toBeUndefined ( ) ;
664+ } ) ;
665+
666+ it ( 'should not have callees for type aliases' , async ( ) => {
667+ const result = await scanRepository ( {
668+ repoRoot,
669+ include : [ 'packages/core/src/scanner/types.ts' ] ,
670+ } ) ;
671+
672+ // Type aliases don't have callees
673+ const typeAlias = result . documents . find ( ( d ) => d . metadata . name === 'DocumentType' ) ;
674+ expect ( typeAlias ) . toBeDefined ( ) ;
675+ expect ( typeAlias ?. metadata . callees ) . toBeUndefined ( ) ;
676+ } ) ;
677+
678+ it ( 'should deduplicate callees at same line' , async ( ) => {
679+ const result = await scanRepository ( {
680+ repoRoot,
681+ include : [ 'packages/core/src/scanner/index.ts' ] ,
682+ } ) ;
683+
684+ const fn = result . documents . find ( ( d ) => d . metadata . name === 'createDefaultRegistry' ) ;
685+ expect ( fn ?. metadata . callees ) . toBeDefined ( ) ;
686+
687+ // Check for no duplicates (same name + same line)
688+ const seen = new Set < string > ( ) ;
689+ for ( const callee of fn ?. metadata . callees || [ ] ) {
690+ const key = `${ callee . name } :${ callee . line } ` ;
691+ expect ( seen . has ( key ) ) . toBe ( false ) ;
692+ seen . add ( key ) ;
693+ }
694+ } ) ;
695+
696+ it ( 'should handle method calls on objects' , async ( ) => {
697+ const result = await scanRepository ( {
698+ repoRoot,
699+ include : [ 'packages/core/src/scanner/index.ts' ] ,
700+ } ) ;
701+
702+ const fn = result . documents . find ( ( d ) => d . metadata . name === 'createDefaultRegistry' ) ;
703+ expect ( fn ?. metadata . callees ) . toBeDefined ( ) ;
704+
705+ // Should have registry.register() calls
706+ const calleeNames = fn ?. metadata . callees ?. map ( ( c ) => c . name ) || [ ] ;
707+ expect ( calleeNames . some ( ( n ) => n . includes ( 'register' ) ) ) . toBe ( true ) ;
708+ } ) ;
709+ } ) ;
597710} ) ;
0 commit comments