@@ -707,4 +707,170 @@ describe('Scanner', () => {
707707 expect ( calleeNames . some ( ( n ) => n . includes ( 'register' ) ) ) . toBe ( true ) ;
708708 } ) ;
709709 } ) ;
710+
711+ describe ( 'Arrow Function Extraction' , ( ) => {
712+ // Note: We override exclude to allow fixtures directory (excluded by default)
713+ const fixtureExcludes = [ '**/node_modules/**' , '**/dist/**' ] ;
714+
715+ it ( 'should extract arrow functions assigned to variables' , async ( ) => {
716+ const result = await scanRepository ( {
717+ repoRoot,
718+ include : [ 'packages/core/src/scanner/__tests__/fixtures/arrow-functions.ts' ] ,
719+ exclude : fixtureExcludes ,
720+ } ) ;
721+
722+ // Should find arrow function variables
723+ const variables = result . documents . filter ( ( d ) => d . type === 'variable' ) ;
724+ expect ( variables . length ) . toBeGreaterThan ( 0 ) ;
725+ } ) ;
726+
727+ it ( 'should mark arrow functions with isArrowFunction metadata' , async ( ) => {
728+ const result = await scanRepository ( {
729+ repoRoot,
730+ include : [ 'packages/core/src/scanner/__tests__/fixtures/arrow-functions.ts' ] ,
731+ exclude : fixtureExcludes ,
732+ } ) ;
733+
734+ const arrowFn = result . documents . find (
735+ ( d ) => d . type === 'variable' && d . metadata . name === 'simpleArrow'
736+ ) ;
737+ expect ( arrowFn ) . toBeDefined ( ) ;
738+ expect ( arrowFn ?. metadata . isArrowFunction ) . toBe ( true ) ;
739+ } ) ;
740+
741+ it ( 'should detect React hooks by naming convention' , async ( ) => {
742+ const result = await scanRepository ( {
743+ repoRoot,
744+ include : [ 'packages/core/src/scanner/__tests__/fixtures/arrow-functions.ts' ] ,
745+ exclude : fixtureExcludes ,
746+ } ) ;
747+
748+ const hook = result . documents . find (
749+ ( d ) => d . type === 'variable' && d . metadata . name === 'useCustomHook'
750+ ) ;
751+ expect ( hook ) . toBeDefined ( ) ;
752+ expect ( hook ?. metadata . isHook ) . toBe ( true ) ;
753+ expect ( hook ?. metadata . isArrowFunction ) . toBe ( true ) ;
754+ } ) ;
755+
756+ it ( 'should detect async arrow functions' , async ( ) => {
757+ const result = await scanRepository ( {
758+ repoRoot,
759+ include : [ 'packages/core/src/scanner/__tests__/fixtures/arrow-functions.ts' ] ,
760+ exclude : fixtureExcludes ,
761+ } ) ;
762+
763+ const asyncFn = result . documents . find (
764+ ( d ) => d . type === 'variable' && d . metadata . name === 'fetchData'
765+ ) ;
766+ expect ( asyncFn ) . toBeDefined ( ) ;
767+ expect ( asyncFn ?. metadata . isAsync ) . toBe ( true ) ;
768+ } ) ;
769+
770+ it ( 'should extract exported arrow functions' , async ( ) => {
771+ const result = await scanRepository ( {
772+ repoRoot,
773+ include : [ 'packages/core/src/scanner/__tests__/fixtures/arrow-functions.ts' ] ,
774+ exclude : fixtureExcludes ,
775+ } ) ;
776+
777+ const exportedFn = result . documents . find (
778+ ( d ) => d . type === 'variable' && d . metadata . name === 'exportedArrow'
779+ ) ;
780+ expect ( exportedFn ) . toBeDefined ( ) ;
781+ expect ( exportedFn ?. metadata . exported ) . toBe ( true ) ;
782+ } ) ;
783+
784+ it ( 'should extract non-exported arrow functions' , async ( ) => {
785+ const result = await scanRepository ( {
786+ repoRoot,
787+ include : [ 'packages/core/src/scanner/__tests__/fixtures/arrow-functions.ts' ] ,
788+ exclude : fixtureExcludes ,
789+ } ) ;
790+
791+ const privateFn = result . documents . find (
792+ ( d ) => d . type === 'variable' && d . metadata . name === 'privateHelper'
793+ ) ;
794+ expect ( privateFn ) . toBeDefined ( ) ;
795+ expect ( privateFn ?. metadata . exported ) . toBe ( false ) ;
796+ } ) ;
797+
798+ it ( 'should extract function expressions assigned to variables' , async ( ) => {
799+ const result = await scanRepository ( {
800+ repoRoot,
801+ include : [ 'packages/core/src/scanner/__tests__/fixtures/arrow-functions.ts' ] ,
802+ exclude : fixtureExcludes ,
803+ } ) ;
804+
805+ const funcExpr = result . documents . find (
806+ ( d ) => d . type === 'variable' && d . metadata . name === 'legacyFunction'
807+ ) ;
808+ expect ( funcExpr ) . toBeDefined ( ) ;
809+ expect ( funcExpr ?. metadata . isArrowFunction ) . toBe ( false ) ;
810+ } ) ;
811+
812+ it ( 'should include signature for arrow functions' , async ( ) => {
813+ const result = await scanRepository ( {
814+ repoRoot,
815+ include : [ 'packages/core/src/scanner/__tests__/fixtures/arrow-functions.ts' ] ,
816+ exclude : fixtureExcludes ,
817+ } ) ;
818+
819+ const fn = result . documents . find (
820+ ( d ) => d . type === 'variable' && d . metadata . name === 'typedArrow'
821+ ) ;
822+ expect ( fn ) . toBeDefined ( ) ;
823+ expect ( fn ?. metadata . signature ) . toContain ( 'typedArrow' ) ;
824+ expect ( fn ?. metadata . signature ) . toContain ( '=>' ) ;
825+ } ) ;
826+
827+ it ( 'should extract callees from arrow functions' , async ( ) => {
828+ const result = await scanRepository ( {
829+ repoRoot,
830+ include : [ 'packages/core/src/scanner/__tests__/fixtures/arrow-functions.ts' ] ,
831+ exclude : fixtureExcludes ,
832+ } ) ;
833+
834+ const fn = result . documents . find (
835+ ( d ) => d . type === 'variable' && d . metadata . name === 'composedFunction'
836+ ) ;
837+ expect ( fn ) . toBeDefined ( ) ;
838+ expect ( fn ?. metadata . callees ) . toBeDefined ( ) ;
839+ expect ( fn ?. metadata . callees ?. length ) . toBeGreaterThan ( 0 ) ;
840+ } ) ;
841+
842+ it ( 'should extract JSDoc from arrow functions' , async ( ) => {
843+ const result = await scanRepository ( {
844+ repoRoot,
845+ include : [ 'packages/core/src/scanner/__tests__/fixtures/arrow-functions.ts' ] ,
846+ exclude : fixtureExcludes ,
847+ } ) ;
848+
849+ const fn = result . documents . find (
850+ ( d ) => d . type === 'variable' && d . metadata . name === 'documentedArrow'
851+ ) ;
852+ expect ( fn ) . toBeDefined ( ) ;
853+ expect ( fn ?. metadata . docstring ) . toBeDefined ( ) ;
854+ expect ( fn ?. metadata . docstring ) . toContain ( 'documented' ) ;
855+ } ) ;
856+
857+ it ( 'should not extract variables without function initializers' , async ( ) => {
858+ const result = await scanRepository ( {
859+ repoRoot,
860+ include : [ 'packages/core/src/scanner/__tests__/fixtures/arrow-functions.ts' ] ,
861+ exclude : fixtureExcludes ,
862+ } ) ;
863+
864+ // Should NOT find plain constants
865+ const constant = result . documents . find (
866+ ( d ) => d . type === 'variable' && d . metadata . name === 'plainConstant'
867+ ) ;
868+ expect ( constant ) . toBeUndefined ( ) ;
869+
870+ const objectConst = result . documents . find (
871+ ( d ) => d . type === 'variable' && d . metadata . name === 'configObject'
872+ ) ;
873+ expect ( objectConst ) . toBeUndefined ( ) ;
874+ } ) ;
875+ } ) ;
710876} ) ;
0 commit comments